Azure Synapse Analytics 中針對專用 SQL 集區的 GROUP BY 選項

在本文中,您將找到在專用 SQL 集區中實作 GROUP BY 選項的祕訣。

GROUP BY 有什麼用途?

GROUP BY T-SQL 子句可將資料彙總至摘要的一組資料列。 GROUP BY 有些選項不支援專用 SQL 集區。 這些選項有如下因應措施:

  • GROUP BY 搭配 ROLLUP
  • GROUPING SETS
  • GROUP BY 搭配 CUBE

Rollup 和 grouping sets 選項

此處最簡單的選項是使用 UNION ALL 來執行彙總,而不依賴明確的語法。 結果完全相同。

下列範例使用 GROUP BY 陳述式搭配 ROLLUP 選項:

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,上述範例會要求下列彙總:

  • 國家及區域
  • Country
  • 總計

若要取代 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 區段。

Cube 選項

您可以使用 UNION ALL 方法建立 GROUP BY WITH CUBE。 問題是程式碼可能很快就會很麻煩且不易處理。 若要避免此問題,您可以使用這項更進階的方法。

使用上述範例,第一個步驟是定義 'cube',以定義我們想要建立的所有彙總層級。

請記下兩個衍生資料表的 CROSS JOIN,因為這可替我們產生所有層級。 其餘的程式碼則是用於格式化:

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;

下列影像顯示 CTAS 的結果:

Group by cube

第二個步驟是指定目標資料表來儲存過渡結果:

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
;

將程式碼分成區段,並產生迴圈建構,程式碼就會變得更容易管理及維護。

下一步

如需更多開發秘訣,請參閱開發概觀