Hi I have table that has following information
id StoretId itemId Mon Tue Wed
1 1 20 33 10 5
2 1 21 1 0 3
3 1 20 3 2 1
4 2 21 2 1 1
5 2 20 1 1 1
6 2 21 4 4 5
What I am trying to do is to get result by each storeId and total of items for each day by itemId, so it looks like this.
StoreId 1
itemId Mon Tue Wed
20 36 12 6
21 1 0 3
StoreId 2
itemId Mon Tue Wed
20 1 1 1
21 6 5 6
I have done so far if user inputs list of stores to get results for i.e
storelist= [{storeId :1}, {storeId: 2}, {storeId: 3}]
var results= DbContext.Set<stores>()
.Where(x=> storelist.Contains(x.storeId)
.Select(y=> new
{
storeId=y.storeId,
itemsdetails= DbContext.Set<maintable>()
.Select(m=> new
{
itemId=m.itemId.Distinct(),
Mon=m.Mon.Sum(),
Tue=m.Tue.Sum(),
Wed=m.Wed.Sum()
}
}
Query conceptually looks fine but it breaks and doesn't give result. Please let me know how to fix it to get the desired output.
Thanks
You should use GroupBy to group by store and then select the columns by the sum of the group
var result = list.GroupBy(o => o.StoreId)
.Select((o, i) => new
{
ID = o.ElementAt(i).ID,
StoreId = o.Key,
Mon = o.Sum(x => x.Mon),
Tue = o.Sum(x => x.Tue),
Wed = o.Sum(x => x.Wed),
}).ToList();
must be grouped by both StoreID and ItemID
and select sum of other values as result:
var result = from item in list
group item by new
{
item.StoreID,
item.ItemID
} into groupList
select new
{
StoreID = groupList.Key.StoreID,
ItemID = groupList.Key.ItemID,
mon = groupList.Sum(i => i.mon),
tue = groupList.Sum(i => i.tue),
wed = groupList.Sum(i => i.wed)
};
Related
This is how my table data looks like ,
Id C1 C2 C3
-------------------------------------------------
1 John 1990 A
2 John 1990 B
3 John 2000 C
4 Mary 2001 D
5 Mary 2010 E
6 Mary 2010 F
7 Jack 2010 G
8 Jack 2010 H
9 Jack 2011 I
What I want to do is I want to group by C1,C2 columns and get the first items of each group which is order by C3 column descending.
So the result will be like
Id C1 C2 C3
-------------------------------------------------
1 John 1990 B
3 John 2000 C
4 Mary 2001 D
5 Mary 2010 F
7 Jack 2010 H
9 Jack 2011 I
And I also want to filter row number 2 to 5 using skip and take function.
So the Final result should be like
Id C1 C2 C3
-------------------------------------------------
3 John 2000 C
4 Mary 2001 D
5 Mary 2010 F
7 Jack 2010 H
What I have tried is
await data.GroupBy(d => new { d.C1, d.C2 }).Skip(1).Take(4).FirstAsync();
But it only retrun one row.
How can I solve for this ?
You need to do a Select and since there will be multiple results you'd need to use ToListAsync instead.
data.GroupBy(d => new { d.C1, d.C2 })
.Select(grp => grp.First())
.Skip(1)
.Take(4)
.ToListAsync();
You can do it by,
using System;
using System.Linq;
using System.Collections.Generic;
...
var result = await data.GroupBy(d => new { d.C1, d.C2 }) //Group by C1 and C2
.Select(s => s.First()) //Select first record from each Group
.Skip(1) //Skip first record
.Take(4) //Pick up next 4 records
.ToListAsync() //Convert 4 records to List.
I have two Table1 and Table2 whose columns with the values are given below:
These are the two tables:
I want to update "PaidAmount" in Table1. Join based on "InvoiceNo" column in both the tables.
Table1:
InvoiceNo Vendor InvoiceValue InvoiceDate PaidAmount
--------- ------ ------------- ----------- ----------
1 AA 15000 01 Dec 2013 0
2 BB 20000 10 Dec 2013 0
3 CC 10000 18 Dec 2013 0
Table2:
VoucherNo Date InvoiceNo Amount
------- ----------- ---------- ------
001 01 Nov 2013 1 5000
002 10 Nov 2013 2 6000
003 20 Nov 2013 3 7000
001 02 Nov 2013 1 2000
My desired datatable should be like this:
DesiredTable:
InvoiceNo Vendor InvoiceValue InvoiceDate PaidAmount
--------- ------ ------------- ----------- ----------
1 AA 15000 01 Dec 2013 7000
2 BB 20000 10 Dec 2013 6000
3 CC 10000 18 Dec 2013 7000
How to achieve this result?
I have tried the below one.
Table1.AsEnumerable().Join(Table2.AsEnumerable(),
dt1_Row => dt1_Row.ItemArray[0],
dt2_Row => dt2_Row.ItemArray[2],
dt1_Row, dt2_Row) => new { dt1_Row, dt2_Row }
).ToList()
.ForEach(o => o.dt1_Row.SetField(4, o.dt2_Row.ItemArray[3]));
But it gives the result as
InvoiceNo Vendor InvoiceValue InvoiceDate PaidAmount
--------- ------ ------------- ----------- ----------
1 AA 15000 01 Dec 2013 2000
2 BB 20000 10 Dec 2013 6000
3 CC 10000 18 Dec 2013 7000
How to get my desired table?
Your join give you a list of multiple row1, row2 couple.
So you are looping throught every couple, the first time for invoiceNo1, row1.PaidAmount = 5000, then your loop continue, and the second time, row1.PaidAmount = 2000, so your result.
You want to sum the Amount values of row2, so after joining, you have to group the datas by InvoiceValue, then perform a sum:
foreach(var grp in Table1.AsEnumerable()
.Join(Table2.AsEnumerable(),
dt1_Row => dt1_Row.ItemArray[0],
dt2_Row => dt2_Row.ItemArray[2],
dt1_Row, dt2_Row) => new { dt1_Row, dt2_Row }
)
.GroupBy(o => o.dt1_Row.ItemArray[0]))
{
var row1 = grp.First().dt1_Row;
var sum = grp.Sum(t => Convert.ToDecimal(t.dt2_Row.ItemArray[3]));
row1.SetField(4, sum)
}
For more readibility, try to avoid using ForEach of List, it doesn't really improve your code.
It looks like you're iterating through your results and overwriting as opposed to adding to the pre-existing result from other rows. You would likely want to do something like this:
Table1.AsEnumerable().Join(Table2.AsEnumerable(),
dt1_Row => dt1_Row.ItemArray[0],
dt2_Row => dt2_Row.ItemArray[2],
dt1_Row, dt2_Row) => new { dt1_Row, dt2_Row }
).ToList()
.ForEach(o => o.dt1_Row.SetField(4, o.dt1_Row.ItemArray[4] + o.dt2_Row.ItemArray[3]));
Here's one approach. You could use GroupBy to create invoice-groups and ToDictionary to create an efficient InvoiceNo to PaidAmount lookup. Then you just need a loop to update the rows:
var invoiceGroups = from r1 in Table1.AsEnumerable()
join r2 in Table2.AsEnumerable()
on r1.Field<int>("InvoiceNo") equals r2.Field<int>("InvoiceNo")
group r2 by r2.Field<int>("InvoiceNo") into InvoiceGroup
select InvoiceGroup;
Dictionary<int, int> invoiceSumLookup = invoiceGroups
.ToDictionary(ig => ig.Key, ig => ig.Sum(r => r.Field<int>("Amount")));
foreach(DataRow row in Table1.Rows)
row.SetField("PaidAmount", invoiceSumLookup[row.Field<int>("InvoiceNo")]);
Note that this does not delete duplicate InvoiceNo rows from Table1 if that's possible and not desired. It just groups the second table by that column and sums all Amounts.
It modifies the original table and does not need to create a new one.
I have a DataTable called "DTHead" which has the following records,
MIVID Quantity Value
------ ---------- --------
1 10 3000
1 20 3500
1 15 2000
2 20 3000
2 50 7500
3 25 2000
Here, I need to split the above DataTable into three tables based on the MIVID such as follows;
DTChild1:
MIVID Quantity Value
------- ---------- ---------
1 10 3000
1 20 3500
1 15 2000
DTChild2:
MIVID Quantity Value
------- ---------- ---------
2 20 3000
2 50 7500
DTChild3:
MIVID Quantity Value
------- ---------- ---------
3 25 2000
Suppose, if the Header DataTable contains 4 different MIVID means, then 4 Child DataTable should be created based on the MIVID. How to do this?
Use LINQ to DataTable to group the first column by GroupBy, and use method CopyToDataTable to copy list of rows to DataTable
List<DataTable> result = DTHead.AsEnumerable()
.GroupBy(row => row.Field<int>("MIVID"))
.Select(g => g.CopyToDataTable())
.ToList();
Then you can get the result as a list of DataTables as you expected.
DataTable tbl = new DataTable("Data").AsEnumerable()
.Where(r => r.Field<int>("ParentId") == 1) // ParentId == 1
.Where(r => r.Field<int>("Id") > 3) // Id > 3
.Where(r => r.Field<string>("Name").Contains("L")) // Name contains L
.OrderBy(r => r.Field<int>("Id")) // Order by Id
.CopyToDataTable();
i have a model as below
ID Date BoitierNumber
1 07/04/2012 14:01:46 1
2 07/04/2012 14:01:50 2
3 07/04/2012 14:01:50 3
4 07/04/2012 14:01:56 1
5 07/04/2012 14:02:06 1
6 07/04/2012 14:02:10 2
I have grouped rows by (BoitierNumber)
*boitier Number 1
1 07/04/2012 14:01:46
4 07/04/2012 14:01:56
5 07/04/2012 14:02:06
*boitier Number 2
2 07/04/2012 14:01:50
6 07/04/2012 14:02:10
*boitier Number 3
3 07/04/2012 14:01:50
To do this i have used this code
var groups = context.Essais.GroupBy(p => p.BoitierNumber)
.Select(g => new { GroupName = g.Key, Members = g });
foreach (var g in groups)
{
Console.WriteLine("Members of {0}", g.GroupName);
foreach (var member in g.Members.OrderBy(x=>x.Id))
{
Console.WriteLine("{0} {1}", member.Id,member.Date);
}
}
For the moment everything works fine
now i want to compare the date of two successives grouped rows
if row[i].date>row[i-1].date i will delete row[i-1]
For example:
*boitier Number 1
1 07/04/2012 14:01:46
4 07/04/2012 14:01:56
5 07/04/2012 14:02:06
8 07/04/2012 14:01:00
10 07/04/2012 14:00:00
13 07/04/2012 14:03:00
boitier Number 1
---> Date of row of Id 4 > Date of row of ID 1
then i will delete row of ID 1
---> Date of row of Id 5 > Date of row of ID 4
then i will delete row of ID 4
---> Date of row of Id 8 < Date of row of ID 5
then i will skip it
---> Date of row of Id 10 < Date of row of ID 8
then i will skip it
---> Date of row of Id 13 > Date of row of ID 10
then i will delete row of ID 10
...
TherFore, After this process, only rows 13 and 8 will be remain
The fastest change you can do now is:
var groups = context.Essais.GroupBy(p => p.BoitierNumber)
.Select(g => new
{
GroupName = g.Key,
Members = g.OrderBy(m=>m.Id)
});
EDIT
It seems EF doesn't work with calling ToList() in the projection.
The Members will be now an ordered list by id, then you can do a for instead a foreach
foreach (var g in groups)
{
var members = g.Members.ToList();
for (int i = 1, i < members.Count; i++)
{
var previousMember = members[i-1];
var currentMember = members[i];
if (..)
// code to delete
}
}
Just a note. Projecting the grouped Members with the initial query, it will create other queries to select the members corresponding to the each group key. You'll still load the entire table, but in subsequent queries. You can do the grouping in memory:
var groups = context.Essais
.AsEnumberable().
.GroupBy(p => p.BoitierNumber)
.Select(g => new { GroupName = g.Key, Members = g.OrderBy(m=>m.Id).ToList() });
I have the following list
ID Counter SrvID FirstName
-- ------ ----- ---------
1 34 66M James
5 34 66M Keith
3 55 45Q Jason
2 45 75W Mike
4 33 77U Will
What I like to do is to order by ID by ascending and then
get the first value of Counter, SrvID which are identical (if any).
So the output would be something like:
ID Counter SrvID FirstName
-- ------ ----- ---------
1 34 66M James
2 45 75W Mike
3 55 45Q Jason
4 33 77U Will
Note how ID of 5 is removed from the list as Counter and SrvID was identical to what I had for ID 1 but as ID 1 came first
I removed 5.
This is what I would do but not working
var result = (from ls in list1
group ts by new {ls.Counter, ls.SrvID}
order by ls.ID
select new{
ls.ID,
ls.Counter.FirstOrDefault(),
ls.SrvID.First,
ls.FirstName}).ToList()
list1.GroupBy(item => new { Counter = item.Counter, SrvID = item.SrvID })
.Select(group => new {
ID = group.First().ID,
Counter = group.Key.Counter,
SrvID = group.Key.SrvID,
FirstName = group.First().FirstName})
.OrderBy(item => item.ID);
Group the records up, and pick a winner from each group.
var query =
from record in list1
group record by new {record.Counter, record.SrvID } into g
let winner =
(
from groupedItem in g
order by groupedItem.ID
select groupedItem
).First()
select winner;
var otherQuery = list1
.GroupBy(record => new {record.Counter, record.SrvID })
.Select(g => g.OrderBy(record => record.ID).First());