通过


你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

Synapse SQL 中的 GROUP BY 选项

Synapse SQL 允许通过实现不同的 GROUP BY 选项来开发解决方案。

GROUP BY 的作用

GROUP BY T-SQL 子句将数据聚合到汇总行集。

无服务器 SQL 池不支持 GROUP BY 选项。 专用 SQL 池支持有限数量的 GROUP BY 选项。

专用 SQL 池支持的 GROUP BY 选项

GROUP BY 有一些专用 SQL 池不支持的选项。 这些选项具有解决方法,如下所示:

  • 带有 ROLLUP 的 GROUP BY
  • 分组设置
  • 将 GROUP BY 与 CUBE 配合使用

汇总和分组集选项

此处最简单的选项是使用 UNION ALL 来执行汇总,而不是依赖于显式语法。 结果完全相同

以下示例使用带有 ROLLUP 选项的 GROUP BY 语句:

SELECT [SalesTerritoryCountry]
,      [SalesTerritoryRegion]
,      SUM(SalesAmount)             AS TotalSalesAmount
FROM  dbo.factInternetSales s
JOIN  dbo.DimSalesTerritory t       ON s.SalesTerritoryKey       = t.SalesTerritoryKey
GROUP BY ROLLUP (
                        [SalesTerritoryCountry]
                ,       [SalesTerritoryRegion]
                )
;

使用 ROLLUP,前面的示例请求以下聚合:

  • 国家/地区
  • 国家
  • 总计

若要替换 ROLLUP 并返回相同的结果,可以使用 UNION ALL 并显式指定所需的聚合:

SELECT [SalesTerritoryCountry]
,      [SalesTerritoryRegion]
,      SUM(SalesAmount) AS TotalSalesAmount
FROM  dbo.factInternetSales s
JOIN  dbo.DimSalesTerritory t     ON s.SalesTerritoryKey       = t.SalesTerritoryKey
GROUP BY
       [SalesTerritoryCountry]
,      [SalesTerritoryRegion]
UNION ALL
SELECT [SalesTerritoryCountry]
,      NULL
,      SUM(SalesAmount) AS TotalSalesAmount
FROM  dbo.factInternetSales s
JOIN  dbo.DimSalesTerritory t     ON s.SalesTerritoryKey       = t.SalesTerritoryKey
GROUP BY
       [SalesTerritoryCountry]
UNION ALL
SELECT NULL
,      NULL
,      SUM(SalesAmount) AS TotalSalesAmount
FROM  dbo.factInternetSales s
JOIN  dbo.DimSalesTerritory t     ON s.SalesTerritoryKey       = t.SalesTerritoryKey;

若要替换 GROUPING SETS,示例原则适用。 只需为要查看的聚合级别创建 UNION ALL 部分。

多维数据集选项

可以使用 UNION ALL 方法创建 GROUP BY WITH CUBE。 问题是,代码会迅速变得繁琐且难以管理。 若要缓解此问题,可以使用此更高级的方法。

第一步是定义“cube”,它定义我们想要创建的所有聚合级别。 记下两个派生表的交叉联接,因为这会生成所有级别。 其余代码用于设置格式。

CREATE TABLE #Cube
WITH
(   DISTRIBUTION = ROUND_ROBIN
,   LOCATION = USER_DB
)
AS
WITH GrpCube AS
(SELECT    CAST(ISNULL(Country,'NULL')+','+ISNULL(Region,'NULL') AS NVARCHAR(50)) as 'Cols'
,          CAST(ISNULL(Country+',','')+ISNULL(Region,'') AS NVARCHAR(50))  as 'GroupBy'
,          ROW_NUMBER() OVER (ORDER BY Country) as 'Seq'
FROM       ( SELECT 'SalesTerritoryCountry' as Country
             UNION ALL
             SELECT NULL
           ) c
CROSS JOIN ( SELECT 'SalesTerritoryRegion' as Region
             UNION ALL
             SELECT NULL
           ) r
)
SELECT Cols
,      CASE WHEN SUBSTRING(GroupBy,LEN(GroupBy),1) = ','
            THEN SUBSTRING(GroupBy,1,LEN(GroupBy)-1)
            ELSE GroupBy
       END AS GroupBy  --Remove Trailing Comma
,Seq
FROM GrpCube;

下图显示了 CREATE TABLE AS SELECT 的结果:

按立方体分组

第二步是指定用于存储临时结果的目标表:

DECLARE
 @SQL NVARCHAR(4000)
,@Columns NVARCHAR(4000)
,@GroupBy NVARCHAR(4000)
,@i INT = 1
,@nbr INT = 0
;
CREATE TABLE #Results
(
 [SalesTerritoryCountry] NVARCHAR(50)
,[SalesTerritoryRegion]  NVARCHAR(50)
,[TotalSalesAmount]      MONEY
)
WITH
(   DISTRIBUTION = ROUND_ROBIN
,   LOCATION = USER_DB
)
;

第三步是循环访问执行聚合的列 cube。 查询将在 #Cube 临时表的每一行上运行一次。 结果存储在 #Results 临时表中:

SET @nbr =(SELECT MAX(Seq) FROM #Cube);

WHILE @i<=@nbr
BEGIN
    SET @Columns = (SELECT Cols    FROM #Cube where seq = @i);
    SET @GroupBy = (SELECT GroupBy FROM #Cube where seq = @i);

    SET @SQL ='INSERT INTO #Results
              SELECT '+@Columns+'
              ,      SUM(SalesAmount) AS TotalSalesAmount
              FROM  dbo.factInternetSales s
              JOIN  dbo.DimSalesTerritory t  
              ON s.SalesTerritoryKey = t.SalesTerritoryKey
              '+CASE WHEN @GroupBy <>''
                     THEN 'GROUP BY '+@GroupBy ELSE '' END

    EXEC sp_executesql @SQL;
    SET @i +=1;
END

最后,可以通过读取 #Results 临时表来返回结果。

SELECT *
FROM #Results
ORDER BY 1,2,3
;

通过将代码分解为节并生成循环构造,代码将变得更加可管理且可维护。

后续步骤

有关更多开发技巧,请参阅 开发概述