Perform Join and Group with Linq to SQL? - c#

Hey all. I'm not sure how I could express the following query in C# using Linq to SQL. Here is a short snippet of the pure SQL:
select t1.WholesalerID, t1.RetailerID,
sum(t1.Col1) as 'Column 1',
sum(t2.Col1) as 'Other Column 1',
(sum(t1.Col1) - sum(t2.Col1)) as 'Column 1 Difference',
sum(t1.Col2) as 'Column 2',
sum(t2.Col2) as 'Other Column 2',
(sum(t1.Col2) - sum(t2.Col2)) as 'Column 2 Difference'
from Table1 t1
inner join Table2 t2 on t1.WholesalerID = t2.WholesalerID
group by t1.WholesalerID, t1.RetailerID
Now, I've done Linq to SQL joins and group by's before, but I'm sure how to go about doing these together. I run into the problem when I'm attempting to sum the values from the joined tables. Thanks.

I've reached this solution: (didn't tested it though)
var qry = from t in
(from t1 in Table1
join t2 in Table2 on t1.WholesalerID equals t2.WholesalerID
select new { t1, t2 })
group t by new { t.t1.WholesalerID, t.t1.RetailerID } into g
select new MyTypeWithDifferenceProp
{
WholesalerID = g.Key.WholesalerID,
RetailerID = g.Key.RetailerID,
Column1 = g.Sum(e => e.t1.Col1),
OtherColumn1 = g.Sum(e => e.t2.Col1),
Column2 = g.Sum(e => e.t1.Col2),
OtherColumn2 = g.Sum(e => e.t2.Col2),
};
This MyTypeWithDifferenceProp would have the Column1Difference and Column2Difference already defined.

Related

How to generate left join with in condition using Entity framework core

I can I generate the below SQL query select using entity framework core 3.1.8 ?
SELECT *
FROM table1 t1
LEFT JOIN table2 t2 ON t1.Id = t2.table1Id AND t2.Status IN (1,2,3)
I tried the code below
var statuses = new List<int> { 1, 2, 3 };
var result = await (from t1 in _context.Table1
join t2 in _context.Table2
on t1.Id equals t2.TableId
into results
from m in results.Where(x => statuses.Contains((int)x.Status)).DefaultIfEmpty()
select new ResultDto
{
}).ToListAsync();
But the query generates a suquery
UPDATED
The query suggested by
#Svyatoslav Danyliv generated the SQL below
SELECT [a].[Id], [a].[ActionWith], [a].[CreatedBy], [a].[DateCreated], [t].[table1Id], [t].[Comment], [t].[CreatedBy], [t].[DateCreated]
FROM [Table1] AS [a]
LEFT JOIN (
SELECT [c].[Id], [c].[table1Id], [c].[Comment], [c].[CreatedBy], [c].[DateCreated]
FROM [Table2] AS [c]
WHERE [c].[Status] IN (1, 2)
) AS [t] ON [a].[Id] = [t].[table1Id]
As documented in Collection selector references outer in a where clause, you can rewrite your query in the following way:
var query =
from t1 in _context.Table1
from t2 in _context.Table2
.Where(t1 => t1.Id == t2.TableId && statuses.Contains((int)x.Status))
.DefaultIfEmpty()
select new ResultDto
{
}
Note that GroupJoin has limited translation in EF Core, only simple LEFT JOIN.

Combine two datatable with common column c#

I have two table as below
Table1
IntervalID(pK)
1
2
3
Table 2
IntervalID Name
1 XXX
Output should be (Table1+Table2)
IntervalID Name
1 XXX
2 NULL
3 NULL
I have done like below
Table1.Merge(Table2);
But it does not give desired output
You could achieve this by using Left join, like the following code:
var result = (from t1 in table1
join t2 in table2 on t1.IntervalId equals t2.IntervalId into leftedResults
from leftedResult in leftedResults.DefaultIfEmpty()
select new { t1.IntervalId, Name = leftedResult?.Name }).ToList();
Note that, you can't merge two DataTables that not have similar schemas.
Left join for DataTables :
var result = (from t1 in dataTable1.AsEnumerable()
join t2 in dataTable2.AsEnumerable() on t1.Field<int>("IntervalId") equals t2.Field<int>("IntervalId") into leftedResults
from leftedReult in leftedResults.DefaultIfEmpty()
select new { IntervalId = t1.Field<int>("IntervalId"), Name = leftedReult?.Field<string>("Name") }).ToList();
I hope you find this helpful.

LINQ to SQL Join orderby

i am new to LINQ and joins, so Please forgive me if I am asking it wrong.
I have two tables
Table1
id name date
1 Mike 20-10-15
2 John 21-10-15
3 Sam 23-10-15
Table2
id name date
1 Ashle 19-10-15
2 Lily 21-10-15
3 Jeni 22-10-15
4 April 23-10-15
I need 5 records using Joins and should be orderby Date, most recent records.
Can you guys help me, I really need to figure out how Joins works with orderby.
Thanks
EDIT:
They are two different tables so no foreign key, so I think I can't use Join, so so far what I have done is like this
var combinddata = (from t1 in db.Table1
select t1.id)
.Concat(from t2 in db.Table2
select t2.id);
I don't know how to get only 5 records how to compare records from both tables on DateTime base.
Output should be
Sam
April
Jeni
John
Lily
You can concatenate equal anonymous types from different tables. If you also select the dates, you can sort by them, in descending order, and take the first 5 records:
Table1.Select (t1 =>
new
{
Id = t1.Id,
Name = t1.Name,
Date = t1.Date
}
).Concat(
Table2.Select (t2 =>
new
{
Id = t2.Id,
Name = t2.Name,
Date = t2.Date
}
))
.OrderByDescending (x => x.Date).Take(5)
Note that this gives precedence to items in Table1. If item 5 and 6 in the concatenated result are on the same date, but from Table1 and Table2, respectively, you only get the item from Table1.
If you want, you can select only the names from this result, but I assume that your output only shows the intended order of record, not the exact expected result.
var query =
from Table1 in table1
join Table2 in table2 on table1.id equals table2.id
orderby table1.date ascending
select table1.date;
Try this way
var combinddata = (from t1 in db.Table1
select t1.Name)
.Concat(from t2 in db.Table2
select t2.Name).OrderByDescending(x => x.date).Take(5);

Linq Queries with multiple group by and Scalar valued function

I am trying to write a LINQ query, having multiple group by and scalar valued functions using Entity Framework.
This is a sample query with simpler names:
var test = context.<db_view>.Where(predicate)
.GroupBy(x => new {x.col1, x.col2, x.col3})
.Select(y => new
{
a = y.key.col1,
b = y.key.col2,
c = y.key.col3,
d = ctx.ScalarFunction(y.key.col2)
});
I however get an error:
"Column Distinct1.col1 is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."
I do have col1 in the GROUP BY Clause. Am I missing something here?
This is the SQL Query generated by Entity Framework:
SELECT
1 AS [C1],
[Distinct1].[col1] AS [col1],
[Distinct1].[col2] AS [col2],
[Distinct1].[col3] AS [col3],
[dbo].[scalarfunction]([Distinct1].[col2]) AS [C2],
FROM ( SELECT DISTINCT
[Extent1].[col1] AS [col1],
[Extent1].[col2] AS [col2],
[Extent1].[col3] AS [col3],
FROM (SELECT
[view].[col1] AS [col1],
[view].[col2] AS [col2],
[view].[col3] AS [col3],
[view].[col4] AS [col4],
[view].[col5] AS [col5],
[view].[col6] AS [col6]
FROM [dbo].[view] AS [view]) AS [Extent1]
WHERE (predicate
) AS [Distinct1]
Why use GroupBy? You don't need groups. You just need (col1, col2 col3) distinct tuples.
So use the Distinct operator.
Try this:
var test = context.<db_view>.Where(predicate)
.Select(x => new {x.col1, x.col2, x.col3})
.Distinct()
.Select(y => new
{
a = y.col1,
b = y.col2,
c = y.col3,
d = ctx.ScalarFunction(y.col2)
});

Generate a report from Northwind DB using Linq

I'm trying to generate following report from popular NorthWind DB using Linq. It should be group by Customer, OrderYear.
CustomerName OrderYear Amount
I've to use the following tables Customer,Order and Order Details.
So far this is what I've done.
NorthwindDataContext north = new NorthwindDataContext();
var query = from o in north.Orders
group o by o.Customer.CompanyName into cg
select new
{
Company = cg.Key,
YearGroup = ( from y in cg
group y by y.OrderDate.Value.Year into yg
select new
{
Year = yg.Key,
YearOrdes = yg
}
)
};
foreach (var q in query)
{
Console.WriteLine("Customer Name : " + q.Company);
foreach (var o in q.YearGroup)
{
Console.WriteLine("Year " + o.Year);
Console.WriteLine("Sum " + o.YearOrdes.Sum(yo => yo.Order_Details.Sum( yd=> Convert.ToDecimal(yd.UnitPrice* yd.Quantity))));
}
Console.WriteLine();
}
It is giving me expected results. I compared by running t-sql in back end.But, I've 2 questions.
In the Inner foreach, the 2nd statement generate the sum. Is it proper approach? Or there is better one available?
How to get the Sum in the Linq query itself.
Got it in single LINQ to SQL query:
var query = from o in north.Orders
from c in north.Customers.Where(c => c.CustomerID == o.CustomerID).DefaultIfEmpty()
from d in north.Order_Details.Where(d => d.OrderID == o.OrderID).DefaultIfEmpty()
group new { o, c, d } by new { o.OrderDate.Value.Year, c.CompanyName } into g
select new
{
Company = g.Key.CompanyName,
OrderYear = g.Key.Year,
Amount = g.Sum(e => e.d.UnitPrice * e.d.Quantity)
};
You can then simply get results:
var results = query.ToList();
Or sort it before fetching:
var results = query.OrderBy(g => g.Company).ThenByDescending(g => g.OrderYear).ToList();
I was curious about SQL that is generated by that LINQ to SQL query, so set custom Log and here it is:
SELECT [t5].[value22] AS [Company], [t5].[value2] AS [OrderYear], [t5].[value] AS [Amount]
FROM (
SELECT SUM([t4].[value]) AS [value], [t4].[value2], [t4].[value22]
FROM (
SELECT [t3].[UnitPrice] * (CONVERT(Decimal(29,4),[t3].[Quantity])) AS [value], [t3].[value] AS [value2], [t3].[value2] AS [value22]
FROM (
SELECT DATEPART(Year, [t0].[OrderDate]) AS [value], [t1].[CompanyName] AS [value2], [t2].[UnitPrice], [t2].[Quantity]
FROM [dbo].[Orders] AS [t0]
LEFT OUTER JOIN [dbo].[Customers] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID]
LEFT OUTER JOIN [dbo].[Order Details] AS [t2] ON [t2].[OrderID] = [t0].[OrderID]
) AS [t3]
) AS [t4]
GROUP BY [t4].[value2], [t4].[value22]
) AS [t5]
ORDER BY [t5].[value22], [t5].[value2] DESC
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.6387
A bit scary, isn't it? But if you look closer, there is standard LEFT JOIN used to combine all three tables together! All the rest is just grouping, sorting and summing.

Categories

Resources