From a18729bb85bf60c7fb25b423e00d1d9fa9bce1f4 Mon Sep 17 00:00:00 2001 From: apple <245524539+apples-kksk@users.noreply.github.com> Date: Tue, 12 May 2026 23:15:22 +0800 Subject: [PATCH] Fix grouped count aggregation on SQL Server --- QueryBuilder.Tests/AggregateTests.cs | 26 ++++++++++++++++++++++++++ QueryBuilder/Compilers/Compiler.cs | 24 ++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/QueryBuilder.Tests/AggregateTests.cs b/QueryBuilder.Tests/AggregateTests.cs index 68a69842..9a75e81e 100644 --- a/QueryBuilder.Tests/AggregateTests.cs +++ b/QueryBuilder.Tests/AggregateTests.cs @@ -29,6 +29,20 @@ public void CountMultipleColumns() Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT 1 FROM [A] WHERE [ColumnA] IS NOT NULL AND [ColumnB] IS NOT NULL) AS [countQuery]", c[EngineCodes.SqlServer]); } + [Fact] + public void CountWithGroupBy() + { + var query = new Query("org_storage") + .Select("organization_id") + .LeftJoin("organizations", "org_storage.organization_id", "organizations.id") + .GroupBy("organization_id") + .AsCount(); + + var c = Compile(query); + + Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT [organization_id] FROM [org_storage] \nLEFT JOIN [organizations] ON [org_storage].[organization_id] = [organizations].[id] GROUP BY [organization_id]) AS [countQuery]", c[EngineCodes.SqlServer]); + } + [Fact] public void DistinctCount() { @@ -69,6 +83,18 @@ public void Sum() Assert.Equal("SELECT SUM([PacketsDropped]) AS [sum] FROM [A]", c[EngineCodes.SqlServer]); } + [Fact] + public void SumWithGroupBy() + { + var query = new Query("A") + .GroupBy("UserId") + .AsSum("PacketsDropped"); + + var c = Compile(query); + + Assert.Equal("SELECT SUM([PacketsDropped]) AS [sum] FROM [A] GROUP BY [UserId]", c[EngineCodes.SqlServer]); + } + [Fact] public void Max() { diff --git a/QueryBuilder/Compilers/Compiler.cs b/QueryBuilder/Compilers/Compiler.cs index 5ac6c080..07949b18 100644 --- a/QueryBuilder/Compilers/Compiler.cs +++ b/QueryBuilder/Compilers/Compiler.cs @@ -80,8 +80,25 @@ protected SqlResult PrepareResult(SqlResult ctx) private Query TransformAggregateQuery(Query query) { var clause = query.GetOneComponent("aggregate", EngineCode); + var hasGroup = query.HasComponent("group", EngineCode); - if (clause.Columns.Count == 1 && !query.IsDistinct) return query; + if (clause.Columns.Count == 1 && !query.IsDistinct && (!hasGroup || clause.Type != "count")) return query; + + if (hasGroup && clause.Columns.Count == 1 && !query.IsDistinct) + { + var innerQuery = query.Clone(); + innerQuery.ClearComponent("aggregate", EngineCode); + + var groupedOuterClause = new AggregateClause() + { + Columns = new List { "*" }, + Type = clause.Type + }; + + return new Query() + .AddComponent("aggregate", groupedOuterClause) + .From(innerQuery, $"{clause.Type}Query"); + } if (query.IsDistinct) { @@ -89,7 +106,7 @@ private Query TransformAggregateQuery(Query query) query.ClearComponent("select", EngineCode); query.Select(clause.Columns.ToArray()); } - else + else if (!hasGroup) { foreach (var column in clause.Columns) { @@ -129,8 +146,7 @@ protected virtual SqlResult CompileRaw(Query query) if (query.Method == "aggregate") { query.ClearComponent("limit") - .ClearComponent("order") - .ClearComponent("group"); + .ClearComponent("order"); query = TransformAggregateQuery(query); }