Filter DataTable in c# - c#

I have a datatable like:
ID | ID2
--------
1 | 2
1 | 3
12 | 2
15 | 3
I need to filter data table with ID2(I know two ID2 values in this case 2 and 3) in such a way that i should get output as
ID | ID2
--------
1 | 2
1 | 3
That means ID which have two ID2(2 and 3) should be selected.
dt.Select("ID2=2 AND ID2=3"); is not working in this case.
Thanks

It is not clear what are you searching for.
If you want to extract all the rows in which the same value for the ID column appears two or more times then
DataRow[] rows = dt.Select("Count(ID) > 1)")
You were right, this doesn't work on a datatable without relationships.
I have found a solution usig Linq,
// Returns an IGrouping<int,DataRow> for every ID that appears more than one time
var result = dt.AsEnumerable().GroupBy(z => z.Field<int>("ID"))
.Select(q=> new{Count = q.Count(), ID=q.Key})
.Where(x => x.Count > 1);
// Now we could extract the rows in the usual way
foreach(var l in result)
{
DataRow[] r = dt.Select("ID=" + l.ID);
r.Dump();
}
I don't know how efficient is this, but at least this seems to work

You can use LINQ to DataSet
var rows = table.AsEnumerable().Where(r => r.Field<int>("ID") == 1);
BTW according to desired result you should filter by ID.

Related

EF6 - Return calculated grouped results within a single query

I have a usage table which stores daily usage for customers of various products. I want to now return a result which groups results by customerID for total / combined usage of various products.
See below a perfectly illustrated example of the current data structure :)
id | customerID | prod1 | prod2
1 . 123 . 0 . 1
2 . 125 . 5 . 5
3 . 125 . 1 . 1
I am looking to return a result set as such (again, admire my illustrating ability):
customerID | prod1 | prod2
123 . 0 . 1
125 . 6 . 6
Will this kind of calculation be possible using EF? I am trying to avoid a multitude of loops to achieve the same thing so this would greatly help a brother out.
What you need is GroupBy and Sum:
var result = context.Customers
// .Where(filter) // filter if needed
.GroupBy(m => m.CustomerID)
.Select(g => new
{
CustomerID = g.Key, // We grouped according to CustomerID, so key = CustomerID
SumProd1 = g.Sum(m => m.Prod1), // Sum Prod1 of grouped data
SumProd2 = g.Sum(m => m.Prod2) // Sum Prod2 of grouped data
})
.ToList();
Note: ToList() is for retrieving data, it is not needed if you plan to work on query.

c# Using LiNQ to remove multiple rows in Datatable

This should be simple but i am not able to figure this out. I have a Datatable that has Name, Age where there are rows that have student names, but then multiple rows of special students' Name 'Chris's, and John's. the end result should have a table with all the rows except Chris and John to be combined into one row called Other with the sum of their age.
ie.
NAME | AGE
Tom | 20
John | 15
Peter | 5
John | 2
Tom | 33
Chris | 20
End Result:
NAME | AGE
Tom | 20
Peter | 5
Tom | 33
Other | 37
This is what im doing right now:
var others = table.AsEnumerable().Where(x => x["NAME"].ToString().Equals("Chris") || x["NAME"].ToString().Equals("John"));
var tmpOthers = 0;
foreach (DataRow otherRow in others)
tmpOthers += decimal.Parse(otherRow["AGE"].ToString());
table = table.AsEnumerable().Where(x => !x["NAME"].ToString().Equals("Chris") || !x["NAME"].ToString().Equals("John")).CopyToDataTable();
table.Add(//OTHER-ROW-Here)
This works but i know there must be an easier way to do this in a single LiNQ statement. also i could not put the table.Rows.Remove in the same for loop because of iteration change.
I'd do that using Linq + delegate. Why? A solution with delegate is more elegant and more specific for such of case, because a name may starts with big or small letter. Check below solution:
//delegate to return "Other" for {"Chris","John"} - ignoring case
Func<string, string> GetOtherName = delegate(string s)
{
if(string.Equals(s, "Chris", StringComparison.OrdinalIgnoreCase) ||
string.Equals(s, "John", StringComparison.OrdinalIgnoreCase))
return "Other";
else
return s;
};
//get total age for "Other"
var otherAge = dt.AsEnumerable()
.Where(x=>GetOtherName(x.Field<string>("NAME")) == "Other")
.Select(x=>x.Field<int>("AGE")).Sum();
//remove "Other" rows
dt.AsEnumerable()
.Where(x=>GetOtherName(x.Field<string>("NAME")) == "Other")
.ToList()
.ForEach(r=>r.Delete());
//finally add "other" row
dt.Rows.Add(new object[]{"Other", otherAge});
Result:
NAME AGE
Tom 20
Peter 5
Tom 33
Other 37
For further details, please see: Func Delegate
Well you can use a for loop for that purpose like
for(int i=0; i<others.Count(); i++)
table.Rows.Remove(others[i]);

C# LINQ : Dynamically create property and values that includes sum of a value from a grouped query

My Title is slightly confusing so I will explain it here.
This is my sample query and what I wish to achieve:
var results = from row in toSearch.AsEnumerable()
group by row.Field<String>("Somename") into grp
select new
{
GroupMe = grp.Key,
foreach (var k in someDic.Keys){
TODOPROPERTYNAMEFROMk = grp.sum(x => grp.k);
}
};
This is the general idea of what I want to achieve. Based on a dictionary of keys, I want to create property names from it while summing up the data from the grouped query. The sum will be based off the value of the keys.
toSearch is a datatable and all of the keys of the dictionary makes up some of the headers of the datatable. This to me seems impossible and I have searched up a few sources and one of it (I lost the author sorry....) gave me this solution:
//For generating dynamic objects fr
public static object DynamicProjection(object input, IEnumerable<string> properties)
{
var type = input.GetType();
dynamic dObject = new System.Dynamic.ExpandoObject();
var dDict = dObject as IDictionary<string, object>;
foreach (var p in properties)
{
var field = type.GetField(p);
if (field != null)
dDict[p] = field.GetValue(input);
var prop = type.GetProperty(p);
if (prop != null && prop.GetIndexParameters().Length == 0)
dDict[p] = prop.GetValue(input, null);
}
return dObject;
}
I tried to use it like this
var results = from row in toSearch.AsEnumerable()
group by row.Field<String>("Somename") into grp
select grp;
var test = results.Select( x => DynamicProjection(x,someDic.Keys));
This gave me an object which i could not utilise or at least call properties out from. I would really appreciate any help in achieving what i was originally after and sorry for the long post.
Edit
Expected input is a datatable eg:
Fee | Fi | Fo | Fum
cat | ds | 2 | 93
cow | ff | 5 | 120
cat | ds | 9 | 33
cow | jk | 1 | 133
Group by header: Fee
Headers Received: Fo, Fum
Expected output:
cat | 11 | 126
cow | 6 | 253
Winner: Cow , so adopt a cow *Just joking lol
I'm not quite familiar with ExpandoObject (my arguments may wrong), you could work with Dictionary<columnname, sum>.
I would suggest return a Dictionary with the headers and respective sum.
// ex -- Given following header
List<string> headers = new List<string>();
headers.Add("fo");
headers.Add("fum");
DataTable dt; // Assign correct data source.
var results =dt.AsEnumerable()
.GroupBy(g=>g.Field<string>("fee"))
.Select(x=> new
{
x.Key,
dict = headers.ToDictionary(h=>h, h=>x.Sum(s=>s.Field<int>(h)))
})
.ToList();
This query groups on fee column and calculates sum for a given header columns.
Check this Demo
Output:
Key=cat, column fo , Sum 11, column fum , Sum 126
Key=cow, column fo , Sum 6, column fum , Sum 253

Linq select one occurrence

how can I use link to fetch one-to-one relation that does not contain duplicates? Example:
ID | STATUS
1 | CHECKIN
2 | CHECKOUT
2 | CHECKOUT
1 | CHECKIN
3 | CHECKOUT <--
I should only retrieve the ID 3 CHECKOUT because he is not duplicated.
Can you help me using linq?
You need to make a Group and ask for only group items that = 1
Dim nonDuplicates = (From x In query Group By x.Id, x.Status Into grp = Group
Where grp.Count = 1)
The other answer will still retrieve all the duplicated items, just removing duplicates of them. If you want to only retrieve non-duplicated items, as you stated in your original question, this will work for you:
Item singles = items.Where(i => !items.Any(j => !i.Equals(j) && i.id == j.id));

NHibernate C# e SQL Server

Good Morning,
I wonder if there's any method within the NHIBERNATE to which I can retrieve the first row of the table?
For example:
Line | ID | Name |Last Name |
1 | 0 | Test | of Information |
2 | 1 | Mauricio | Silva |
If I want the first line or the line 1 of the table
You can use Linq to create queries with nHibernate. There is a method called FirstOrDefault() which takes only the first record. If the query return empty, the FirstOrDefault method will return null, so, remember to check the result before using, for sample:
var firstItem = session.Query<Entity>().FirstOrDefault();
if (firstItem != null)
{
string name = firstItem.Name;
// use object
}
NHibernate does support paging, so we can select "any" record using the .Take() and .Skip(). In our case we can do it like this:
var list = session
.QueryOver<Person>()
.Take(1) // this will take just a first record
//.Skip(0) // we can even skip some, to get next page
;
Then the resulting list will contain 1 or none row...
var person = list.FirstOrDefault();
Also, we can never be sure, what order will be used by DB engine, so we should use explicit ORDER BY:
var list = session
.QueryOver<Contact>()
.OrderBy(p => p.ID)
.Asc
.Take(1)
;
Now we can be sure, that the first result will be with ID == 0

Categories

Resources