How to achieve this using Dynamic Linq Join and Dynamic Linq SelectMany
Counting percent of rows with category out of total number of rows using Dynamic Linq
Asked Answered
Desired result is in q and q2.
q shows combination of aggregates from different levels of grouping in one expression.
q2 uses calculated agg from prev levels and generates shorter SQL query.
var grp=(db.A as IQueryable).GroupBy("grp","it");
var grp2=grp.Select("new(key as key,new(count() as cnt) as agg)");
foreach(dynamic r in grp2) Console.WriteLine("grp:"+r.key+"\tcnt:"+r.agg.cnt);
//foreach(dynamic r in grp) Console.WriteLine(r.Key+"\t"+r.Count()); // throws RuntimeBinderException
Console.WriteLine("----------------------");
var cat=(db.A as IQueryable)
.SelectMany("B","new(outer as a,inner as b)")
.GroupBy("new(a.grp,b.cat)","it");
var cat2=cat.Select("new(key as key,new(count() as cnt) as agg)");
foreach(dynamic r in cat2) Console.WriteLine("grp:"+r.key.grp+"\tcat:"+r.key.cat+"\tcnt:"+r.agg.cnt);
Console.WriteLine("----------- result -----------");
var q=cat.Join("c",grp,"g","c.key.grp","g.key","new(g.key as grp,c.key.cat,new(c.count()*100/g.count() as percent) as agg)");
foreach(dynamic r in q) Console.WriteLine("grp:"+r.grp+"\tcat:"+r.cat+"\tpercent:"+r.agg.percent);
Console.WriteLine("----------- result2 -----------");
var q2=cat2.Join("c",grp2,"g","c.key.grp","g.key","new(g.key as grp,c.key.cat,new(c.agg.cnt*100/g.agg.cnt as percent) as agg)");
foreach(dynamic r in q2) Console.WriteLine("grp:"+r.grp+"\tcat:"+r.cat+"\tpercent:"+r.agg.percent);
q produces the following SQL query:
SELECT
1 AS [C1],
[Project4].[grp] AS [grp],
[Project4].[cat] AS [cat],
([Project4].[C1] * 100) / [Project4].[C2] AS [C2]
FROM ( SELECT
[Project3].[cat] AS [cat],
[Project3].[grp] AS [grp],
[Project3].[C1] AS [C1],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[A] AS [Extent6]
WHERE ([Project3].[grp] = [Extent6].[grp]) OR (([Project3].[grp] IS NULL) AND ([Extent6].[grp] IS NULL))) AS [C2]
FROM ( SELECT
[Distinct1].[cat] AS [cat],
[Distinct2].[grp] AS [grp],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[A] AS [Extent4]
INNER JOIN (SELECT
[B].[aid] AS [aid],
[B].[cat] AS [cat]
FROM [dbo].[B] AS [B]) AS [Extent5] ON [Extent4].[id] = [Extent5].[aid]
WHERE (([Distinct1].[grp] = [Extent4].[grp]) OR (([Distinct1].[grp] IS NULL) AND ([Extent4].[grp] IS NULL))) AND ([Distinct1].[cat] = [Extent5].[cat])) AS [C1]
FROM (SELECT DISTINCT
[Extent1].[grp] AS [grp],
[Extent2].[cat] AS [cat]
FROM [dbo].[A] AS [Extent1]
INNER JOIN (SELECT
[B].[aid] AS [aid],
[B].[cat] AS [cat]
FROM [dbo].[B] AS [B]) AS [Extent2] ON [Extent1].[id] = [Extent2].[aid] ) AS [Distinct1]
INNER JOIN (SELECT DISTINCT
[Extent3].[grp] AS [grp]
FROM [dbo].[A] AS [Extent3] ) AS [Distinct2] ON ([Distinct1].[grp] = [Distinct2].[grp]) OR (([Distinct1].[grp] IS NULL) AND ([Distinct2].[grp] IS NULL))
) AS [Project3]
) AS [Project4]
q2 produces shorter SQL query:
SELECT
1 AS [C1],
[GroupBy2].[K1] AS [grp],
[GroupBy1].[K2] AS [cat],
([GroupBy1].[A1] * 100) / [GroupBy2].[A1] AS [C2]
FROM (SELECT
[Extent1].[grp] AS [K1],
[Extent2].[cat] AS [K2],
COUNT(1) AS [A1]
FROM [dbo].[A] AS [Extent1]
INNER JOIN (SELECT
[B].[aid] AS [aid],
[B].[cat] AS [cat]
FROM [dbo].[B] AS [B]) AS [Extent2] ON [Extent1].[id] = [Extent2].[aid]
GROUP BY [Extent1].[grp], [Extent2].[cat] ) AS [GroupBy1]
INNER JOIN (SELECT
[Extent3].[grp] AS [K1],
COUNT(1) AS [A1]
FROM [dbo].[A] AS [Extent3]
GROUP BY [Extent3].[grp] ) AS [GroupBy2] ON ([GroupBy1].[K1] = [GroupBy2].[K1]) OR (([GroupBy1].[K1] IS NULL) AND ([GroupBy2].[K1] IS NULL))
Pretty sure this doesn't work. The method signatures don't even match. –
Arabela
@Hovito Sorry I did not mention this dynamic join implementation that I use –
Sonni
© 2022 - 2024 — McMap. All rights reserved.