Желаемый результат в q и q2.
q показывает комбинацию агрегатов с разных уровней группировки в одном выражении.
q2 использует вычисленную агг из предыдущих уровней и генерирует более короткий запрос SQL.
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 создает следующий SQL-запрос:
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 создает более короткий запрос SQL:
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))