I have the following C# models:
public class RawData
{
public int questionnaireId { get; set; }
public int coachNodeId { get; set; }
public int questionnaireNumber { get; set; }
public float score { get; set; }
}
public class AveragedData
{
public int coachNodeId { get; set; }
public int questionnaireNumber { get; set; }
public float averageScore { get; set; }
}
I have an API endpoint which is returning data from a database, mapped as List<RawData>. The values are like this:
questionnaireId | coachNodeId | questionnaireNumber | score
1 | 30 | 1 | 2
2 | 40 | 1 | 3
3 | 30 | 2 | 1
4 | 30 | 3 | 4
5 | 40 | 2 | 5
6 | 40 | 1 | 5
7 | 30 | 1 | 1
8 | 30 | 1 | 2
9 | 40 | 1 | 2
10 | 30 | 2 | 4
What I need to do now, in a LINQ query, is to average out the score values grouped by coachNodeId and questionnaireNumber and return a list of type AveragedData.
The values returned by averaging and grouping the example data above, should be:
coachNodeId | questionnaireNumber | averageScore
30 | 1 | 1.66666666 (calculated by: (2 + 1 + 2) / 3))
30 | 2 | 2.5 (calculated by: (1 + 4) / 2))
30 | 3 | 4 (calculated by: (4 / 1))
40 | 1 | 3.33333333 (calculated by: (3 + 5 + 2) / 3))
40 | 2 | 5 (calculated by: (5 / 1))
I'm not experienced with LINQ so am struggling to put together a query that groups by both coachNodeId and questionnaireNumber and averages the score, returning an object of type List<AveragedData>. Could anyone suggest how to accomplish this?
Many thanks.
assuming you have a List<RawData> called list, you are wanting:
var results = list.GroupBy(x => new
{
questionnaire = x.questionnaireId,
coach = x.coachNodeId
})
.Select(x => new AveragedData
{
coachNodeId = x.Key.coach,
questionnaireNumber = x.Key.questionnaire,
averageScore = x.Average(xx => xx.score)
})
.ToList();
Do the grouping, then use a Select to project the data to your type, using LINQ's Average as well.
Try following :
DataTable dt = new DataTable();
dt.Columns.Add("questionnaireId", typeof(int));
dt.Columns.Add("coachNodeId", typeof(int));
dt.Columns.Add("questionnaireNumber", typeof(int));
dt.Columns .Add("score", typeof(int));
dt.Rows.Add(new object[] {1,30, 1, 2});
dt.Rows.Add(new object[] {2,40, 1, 3});
dt.Rows.Add(new object[] {3,30, 2, 1});
dt.Rows.Add(new object[] {4,30, 3, 4});
dt.Rows.Add(new object[] {5,40, 2, 5});
dt.Rows.Add(new object[] {6,40, 1, 5});
dt.Rows.Add(new object[] {7,30, 1, 1});
dt.Rows.Add(new object[] {8,30, 1, 2});
dt.Rows.Add(new object[] {9,40, 1, 2});
dt.Rows.Add(new object[] {10,30, 2, 4});
var averages = dt.AsEnumerable()
.GroupBy(x => new { coachNodeId = x.Field<int>("coachNodeId"), questionnaireNumber = x.Field<int>("questionnaireNumber") })
.Select(x => new { coachNodeId = x.Key.coachNodeId, questionnaireNumber = x.Key.questionnaireNumber, average = x.Average(y => y.Field<int>("score")) })
.ToList();
Related
I have a many-to-many relationship table that I am trying to do a lookup on like a dictionary.
Item
|---------------------|------------------|-----------------|
| Id | Name | Desc |
|---------------------|------------------|-----------------|
| 1 | One | First Item |
| 2 | Two | Second Item |
| 3 | Three | Third Item |
| 4 | Four | Fourth Item |
| 5 | Five | Fifth Item |
|---------------------|------------------|-----------------|
Collection
|---------------------|------------------|
| Id | Name |
|---------------------|------------------|
| 1 | First Collection |
| 2 | Second Collecton |
|---------------------|------------------|
Inventory
|---------------------|------------------|--------------|
| CollectionId | ItemId | Amount |
|---------------------|------------------|--------------|
| 1 | 1 | 14 |
| 1 | 2 | 4 |
| 1 | 5 | 4 |
| 2 | 1 | 2 |
| 2 | 5 | 9 |
|---------------------|------------------|--------------|
I am trying to design a query to get all CollectionIds where some the CollectionId has a relation to every ItemId in some input set?
It am struggling to find words to describe my intention, but the pseudo code would look like this
SearchFromIncludes(HashSet<Item> list)
{
Dictionary<HashSet<Item>, ItemContainer> lookupTable = MakeTable();
List<ItemContainer> matches = [];
for (key in getKeys(lookupTable))
{
// if all items in the item list exist in the lookup key, add it for return
if (AllItemsExist(key, list))
{
matches.Add(lookupTable.getValue(key));
}
return matches;
}
}
So if MakeTable creates the relationship above as a dictionary
{
[1, 2, 3]: 1,
[1, 5]: 2
}
SearchFromIncludes([1, 5]) would return
[1]
SearchFromIncludes([1, 3, 5]) would return
[1, 2]
Is there a SQL strategy for querying information from a many-to-many table in this way, where you want to get an item from a relation where its related item match an input set exactly? I am thinking GROUP BY may be helpful here but I have not gotten it to work successfully
Ultimately I will be doing this with Entity Framework Core/LINQ, but I would also like to know how this would look as SQL
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable itemTable = new DataTable();
itemTable.Columns.Add("Id", typeof(int));
itemTable.Columns.Add("Name", typeof(string));
itemTable.Columns.Add("Desc", typeof(string));
itemTable.Rows.Add(new object[] { 1, "One", "First Item" });
itemTable.Rows.Add(new object[] { 2, "Two", "Second Item" });
itemTable.Rows.Add(new object[] { 3, "Three", "Third Item" });
itemTable.Rows.Add(new object[] { 4, "Four", "Fourth Item" });
itemTable.Rows.Add(new object[] { 5, "Five", "Fifth Item" });
DataTable collectionTable = new DataTable();
collectionTable.Columns.Add("Id", typeof(int));
collectionTable.Columns.Add("Name", typeof(string));
collectionTable.Rows.Add(new object[] { 1, "First Collection" });
collectionTable.Rows.Add(new object[] { 2, "Second Collection" });
DataTable inventoryTable = new DataTable();
inventoryTable.Columns.Add("CollectionId", typeof(int));
inventoryTable.Columns.Add("ItemId", typeof(int));
inventoryTable.Columns.Add("Amount", typeof(int));
inventoryTable.Rows.Add(new object[] { 1, 1, 14 });
inventoryTable.Rows.Add(new object[] { 1, 2, 4 });
inventoryTable.Rows.Add(new object[] { 1, 5, 4 });
inventoryTable.Rows.Add(new object[] { 2, 1, 2 });
inventoryTable.Rows.Add(new object[] { 2, 5, 9 });
Dictionary<int, List<object>> dict = (from inTable in inventoryTable.AsEnumerable()
join cTable in collectionTable.AsEnumerable() on inTable.Field<int>("CollectionId") equals cTable.Field<int>("Id")
join iTable in itemTable.AsEnumerable() on inTable.Field<int>("ItemId") equals iTable.Field<int>("Id")
select new { inTable = inTable, cTable = cTable, iTable = iTable }
).ToList()
.GroupBy(x => x.cTable.Field<int>("Id"), y => new { itemTableRow = y.iTable, amount = y.inTable.Field<int>("Amount") })
.ToDictionary(x => x.Key, y => y.ToList<object>());
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I need to select fields from unique records within a table with multiple where clauses. I currently am using C# and LINQ fluent syntax connected with NHibernate. So I am wondering if there is a way to create this query that way. Here is a test dataset:
+----+----------+------+------+
| Id | ParentId | Name | Type |
+----+----------+------+------+
| 1 | 100 | A | 1 |
| 2 | 100 | A | 2 |
| 3 | 100 | A | 3 |
| 4 | 200 | B | 1 |
| 5 | 300 | A | 1 |
| 6 | 300 | A | 2 |
| 7 | 400 | A | 1 |
| 8 | 400 | A | 2 |
| 9 | 400 | A | 3 |
| 10 | 400 | A | 4 |
+----+----------+------+------+
I can get the results I want using this SQL query:
SELECT ParentId, COUNT(Name) as Cnt, Max(Id) as Id, Max(Name) as Name, Max(Type) as Type FROM TestGroupBy Where Name = 'A' Group By ParentId;
This gives the result:
+----------+-----+----+------+------+
| ParentId | Cnt | Id | Name | Type |
+----------+-----+----+------+------+
| 100 | 3 | 3 | A | 3 |
| 300 | 2 | 6 | A | 2 |
| 400 | 4 | 10 | A | 4 |
+----------+-----+----+------+------+
I know how to make the group by query but I can't figure out how to do the multiple MAX selects. Is that just not possible with LINQ? If it's not, then what would be a way that I could go about this?
Here's a small snippet that shows you the linq query in context:
public class Row
{
public int Id;
public int ParentId;
public string Name;
public int Type;
public Row(int Id, int ParentId, string Name, int Type)
{
this.Id = Id;
this.ParentId = ParentId;
this.Name = Name;
this.Type = Type;
}
}
class Program
{
static void Main(string[] args)
{
List<Row> test = new List<Row>();
test.Add(new Row(1, 100, "A", 1));
test.Add(new Row(2, 100, "A", 2));
test.Add(new Row(3, 100, "A", 3));
test.Add(new Row(4, 200, "B", 1));
test.Add(new Row(5, 300, "A", 1));
test.Add(new Row(6, 300, "A", 2));
test.Add(new Row(7, 400, "A", 1));
test.Add(new Row(8, 400, "A", 2));
test.Add(new Row(9, 400, "A", 3));
test.Add(new Row(10, 400, "A", 4));
dynamic d = from row in test
where row.Name.Equals("A")
group row by row.ParentId into grp
select new {
ParentId = grp.Key,
Cnt = grp.Count(),
Id = grp.Max(x => x.Id),
Name = grp.Max(x => x.Name),
Type = grp.Max(x => x.Type)
};
}
}
When you have a queryable, you can call Select and pass a predicate. The new keyword constructs an object with the schema you prefer.
.Select( x => new
{
ParentId = x.ParentId
Cnt = x.Count(p => p.Name),
Id = x.Max( p => p.Id )
/*etcetera*/
} );
I need to select the last record of particular columns. I have the following records
WarehouseId | ItemId | SubItemId | DeliveryGroupId | Other Columns
1 | 1 | 1 | 1 | ...
1 | 1 | 1 | 2 | ...
1 | 1 | 1 | 3 | ...
1 | 1 | 2 | 1 | ...
1 | 1 | 2 | 2 | ...
1 | 2 | 1 | 1 | ...
Then I only want to select the MAX(DeliveryGroupId) for each WarehouseId | ItemId | SubItemId. The result should be:
WarehouseId | ItemId | SubItemId | DeliveryGroupId | Other Columns
1 | 1 | 1 | 3 | ...
1 | 1 | 2 | 2 | ...
1 | 2 | 1 | 1 | ...
In SQL, it is very simple to do:
SELECT *
FROM [dbo].[tblOrderDeliveryGroup] t1
WHERE [DeliveryGroupId] IN
(
SELECT MAX([DeliveryGroupId])
FROM [dbo].[tblOrderDeliveryGroup] t2
WHERE (t1.[WarehouseId] = t2.[WarehouseId]) AND (t1.[ItemId] = t2.[ItemId]) AND (t1.[SubItemId] = t2.[SubItemId])
GROUP BY [WarehouseId], [ItemId], [SubItemId]
);
The question is, how do I translate that SQL statement into LINQ-to-SQL?
Thanks
UPDATE
So far, this is my solution. It is very ugly and surely not efficient.
var vLastRecs = (from rec in tblOrderDeliveryGroups.AsNoTracking()
group rec by new { rec.WarehouseId, rec.ItemId, rec.SubItemId } into grec
select new
{
grec.Key.WarehouseId,
grec.Key.ItemId,
grec.Key.SubItemId,
DeliveryGroupId = grec.Max(rec => rec.DeliveryGroupId)
});
return (from rec in tblOrderDeliveryGroups.AsNoTracking()
where vLastRecs.Any(lrec => (rec.WarehouseId == lrec.WarehouseId) && (rec.ItemId == lrec.ItemId) && (rec.SubItemId == lrec.SubItemId) && (rec.DeliveryGroupId == lrec.DeliveryGroupId))
select rec).ToList();
Is it possible to improve it?
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("WarehouseId", typeof(int));
dt.Columns.Add("ItemId", typeof(int));
dt.Columns.Add("SubItemId", typeof(int));
dt.Columns.Add("DeliveryGroupId", typeof(int));
dt.Rows.Add(new object[] {1,1,1,1});
dt.Rows.Add(new object[] {1,1,1,2});
dt.Rows.Add(new object[] {1,1,1,3});
dt.Rows.Add(new object[] {1,1,2,1});
dt.Rows.Add(new object[] {1,1,2,2});
dt.Rows.Add(new object[] {1,2,1,1});
DataTable dt2 = dt.AsEnumerable()
.OrderByDescending(x => x.Field<int>("DeliveryGroupId"))
.GroupBy(x => new { warehouse = x.Field<int>("WarehouseId"), item = x.Field<int>("ItemId"), subitem = x.Field<int>("SubItemId")})
.Select(x => x.FirstOrDefault())
.CopyToDataTable();
}
}
}
Here is a solution using classes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
OrderDeliveryGroups tblOrderDeliverGroups = new OrderDeliveryGroups();
List<AsNoTracking> vLastRecs = tblOrderDeliverGroups.AsNoTracking()
.OrderByDescending(x => x.DeliverGroupId)
.GroupBy(x => new { x.WarehouseId, x.ItemId, x.SubItemId})
.Select(x => x.FirstOrDefault())
.ToList();
}
}
public class OrderDeliveryGroups
{
public List<AsNoTracking> AsNoTracking()
{
return new List<AsNoTracking>() {
new AsNoTracking() { WarehouseId = 1, ItemId = 1, SubItemId = 1, DeliverGroupId = 1 },
new AsNoTracking() { WarehouseId = 1, ItemId = 1, SubItemId = 1, DeliverGroupId = 2 },
new AsNoTracking() { WarehouseId = 1, ItemId = 1, SubItemId = 1, DeliverGroupId = 3 },
new AsNoTracking() { WarehouseId = 1, ItemId = 1, SubItemId = 2, DeliverGroupId = 1 },
new AsNoTracking() { WarehouseId = 1, ItemId = 1, SubItemId = 2, DeliverGroupId = 2 },
new AsNoTracking() { WarehouseId = 1, ItemId = 2, SubItemId = 1, DeliverGroupId = 1 }
};
}
}
public class AsNoTracking
{
public int WarehouseId { get; set; }
public int ItemId { get; set; }
public int SubItemId { get; set; }
public int DeliverGroupId { get; set; }
}
}
I have a problem with getting grouped columns in LINQ.
My class:
public class DTO_CAORAS
{
public int? iORAS_KEY_CON { get; set; }
public int? iMERC_KEY {get;set;}
public double? decD_ORAS_QUA {get;set;}
}
LINQ query:
var results =
from oras in listCAORAS_Delivered
group oras by new
{
oras.iORAS_KEY_CON,
oras.iMERC_KEY
}
into orasGroup
select new
{
decD_ORAS_QUA = orasGroup.Sum(x => x.decD_ORAS_QUA)
};
List results is filled only with one column - decD_ORAS_QUA. I don't know how to get columns, by which query is grouped - IORAS_KEY_CON and iMERC_KEY? I would like to fill results with iORAS_KEY_CON, iMERC_KEY and decD_ORAS_QUA.
Input data:
+---------------+-----------+---------------+
| iORAC_KEY_CON | iMERC_Key | decD_ORAS_QUA |
+---------------+-----------+---------------+
| 1 | 888 | 1 |
| 1 | 888 | 2 |
| 1 | 888 | 4 |
+---------------+-----------+---------------+
Desired output:
+---------------+-----------+---------------+
| iORAC_KEY_CON | iMERC_Key | decD_ORAS_QUA |
+---------------+-----------+---------------+
| 1 | 888 | 7 |
+---------------+-----------+---------------+
To also show the keys:
var results = from oras in listCAORAS_Delivered
group oras by new { oras.iORAS_KEY_CON, oras.iMERC_KEY } into g
select new DTO_CAORAS {
iORAS_KEY_CON = g.Key.iORAS_KEY_CON,
iMERC_KEY = g.Key.iMERC_KEY,
decD_ORAS_QUA = g.Sum(x => x.decD_ORAS_QUA)
};
As you are only grouping one column you can also:
var results = from oras in listCAORAS_Delivered
group oras.decD_ORAS_QUA by new { oras.iORAS_KEY_CON, oras.iMERC_KEY } into g
select new DTO_CAORAS {
iORAS_KEY_CON = g.Key.iORAS_KEY_CON,
iMERC_KEY = g.Key.iMERC_KEY,
decD_ORAS_QUA = g.Sum()
};
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I want to retrieve all records of manufacturer in LINQ using a many-to-many join.
Lets consider
Table 'Item':
id | name
----------
1 | A
---------
2 | B
--------
3 | C
--------
Table 'Manufacturer':
ManufactuerId | Name
-------------------
1 | XYZ
-------------------
2 | ABC
--------------------
3 | ZZZ
----------------------
Table 'ManufacturerItem':
ManufacturerItemID | ManufacturerId | ItemId
-------------------------------------------
1 | 1 | 1
-------------------------------------------
2 | 1 | 2
-------------------------------------------
3 | 2 | 1
------------------------------------------
4 | 3 | 2
------------------------------------------
5 | 1 | 3
------------------------------------------
I would like to fetch the records of a manufacturer(s) who has all the items that I have supplied in.
So, given an input of {A, B} I would like to get an output of XYZ Manufacturer.
var tableItems = new[] {
new { Id = 1, Name = "A" },
new { Id = 2, Name = "B" },
new { Id = 3, Name = "C" }
};
var tableManufacturer = new[] {
new { ManufacturerId = 1, Name = "XYZ" },
new { ManufacturerId = 2, Name = "ABC" },
new { ManufacturerId = 3, Name = "ZZZ" }
};
var tableManufacturerItem = new[]
{
new {ManufacturerItemID = 1, ManufacturerId = 1, ItemId = 1},
new {ManufacturerItemID = 2, ManufacturerId = 1, ItemId = 2},
new {ManufacturerItemID = 3, ManufacturerId = 2, ItemId = 1},
new {ManufacturerItemID = 4, ManufacturerId = 3, ItemId = 2},
new {ManufacturerItemID = 5, ManufacturerId = 1, ItemId = 3},
};
var itemsToSearch = new[] { "A", "B" };
var result = tableManufacturerItem
.GroupBy(x => x.ManufacturerId)
.Where(m => tableItems.Where(item => itemsToSearch.Contains(item.Name)).Select(x => x.Id)
.Except(m.Select(x => x.ItemId))
.Count() == 0)
.Select(x => tableManufacturer.First(m => m.ManufacturerId == x.Key))
.Select(m => m.Name)
.ToList();