GROUPING_ID (Transact-SQL)

Gäller för:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceSQL-databas i Microsoft Fabric

GROUPING_ID Är en funktion som beräknar nivån av gruppering. GROUPING_ID kan endast användas i SELECT <select> listan, HAVING, eller ORDER BY klausuler när GROUP BY anges är specificerad.

Transact-SQL syntaxkonventioner

Syntax

GROUPING_ID ( <column_expression> [ , ...n ] )

Arguments

<column_expression>

En column_expression i en SELECT - GROUP BY-sats .

Returtyper

int

Anmärkningar

De GROUPING_ID <column_expression> måste exakt matcha uttrycket i listan GROUP BY . Till exempel, om du grupperar efter DATEPART (yyyy, <column name>), använd GROUPING_ID (DATEPART (yyyy, <column name>)); eller om du grupperar efter <column name>, använd GROUPING_ID (<column name>).

Jämför GROUPING_ID() med GROUPING()

GROUPING_ID (<column_expression> [ , ...n ]) indata motsvarar avkastningen GROUPING (<column_expression>) för varje kolumn i dess kolumnlistor i varje utdatarad, som en sträng av ettor. och nollor. GROUPING_ID tolkar den strängen som ett bas-2-tal och returnerar motsvarande heltal.

Till exempel, betrakta följande påstående:

SELECT a, b, c, SUM(d),
GROUPING_ID(a, b, c)
FROM T
GROUP BY <group_by_list>

Denna tabell visar GROUPING_ID() in- och utdatavärdena.

Sammanlagda kolumner GROUPING_ID (a, b, c) indata = GRUPPERING(a) + GRUPPERING(b) + GRUPPERING(c) GROUPING_ID() utgång
a 100 4
b 010 2
c 001 1
ab 110 6
ac 101 5
bc 011 3
abc 111 7

Teknisk definition av GROUPING_ID()

Varje GROUPING_ID argument måste vara ett element i listan GROUP BY . GROUPING_ID() returnerar en heltalsbitmap vars lägsta n bitar kan vara belysta. En lit-bit indikerar att motsvarande argument inte är en grupperingskolumn för den givna utdataraden. Den lägsta ordningens biten motsvarar argument n, och den n1-1 lägsta ordningens biten motsvarar argument 1.

GROUPING_ID()-ekvivalenter

För en enskild grupperingsfråga GROUPING (<column_expression>) är ekvivalent med GROUPING_ID (<column_expression>), och båda returnerar 0.

Till exempel är följande påståenden ekvivalenta:

Påstående A

SELECT GROUPING_ID(A, B)
FROM T
GROUP BY CUBE(A, B)

Uttalande B

SELECT 3 FROM T GROUP BY ()
UNION ALL
SELECT 1 FROM T GROUP BY A
UNION ALL
SELECT 2 FROM T GROUP BY B
UNION ALL
SELECT 0 FROM T GROUP BY A, B

Examples

Kodexemplen i den här artikeln använder AdventureWorks2025- eller AdventureWorksDW2025-exempeldatabasen, som du kan ladda ned från startsidan Microsoft SQL Server Samples och Community Projects.

A. Använd GROUPING_ID för att identifiera grupperingsnivåer

Följande exempel returnerar antalet anställda efter Name och Title, samt företagets totala antal i databasen AdventureWorks2025 . GROUPING_ID() används för att skapa ett värde för varje rad i kolumnen Title som identifierar dess aggregeringsnivå.

SELECT D.Name,
    CASE 
        WHEN GROUPING_ID(D.Name, E.JobTitle) = 0 THEN E.JobTitle
        WHEN GROUPING_ID(D.Name, E.JobTitle) = 1 THEN N'Total: ' + D.Name
        WHEN GROUPING_ID(D.Name, E.JobTitle) = 3 THEN N'Company Total:'
        ELSE N'Unknown'
    END AS N'Job Title',
    COUNT(E.BusinessEntityID) AS N'Employee Count'
FROM HumanResources.Employee E
INNER JOIN HumanResources.EmployeeDepartmentHistory DH
    ON E.BusinessEntityID = DH.BusinessEntityID
INNER JOIN HumanResources.Department D
    ON D.DepartmentID = DH.DepartmentID
WHERE DH.EndDate IS NULL
    AND D.DepartmentID IN (12, 14)
GROUP BY ROLLUP(D.Name, E.JobTitle);

B. Använd GROUPING_ID för att filtrera en resultatmängd

Grundläggande exempel

I följande kod, för att endast returnera rader som har antal anställda efter titel, ta bort kommentarstecknen från HAVING GROUPING_ID(D.Name, E.JobTitle) = 0;. För att returnera endast rader med antal anställda per avdelning, ta bort kommentarstecknen från HAVING GROUPING_ID(D.Name, E.JobTitle) = 1;.

SELECT D.Name,
    E.JobTitle,
    GROUPING_ID(D.Name, E.JobTitle) AS [Grouping Level],
    COUNT(E.BusinessEntityID) AS [Employee Count]
FROM HumanResources.Employee AS E
INNER JOIN HumanResources.EmployeeDepartmentHistory AS DH
    ON E.BusinessEntityID = DH.BusinessEntityID
INNER JOIN HumanResources.Department AS D
    ON D.DepartmentID = DH.DepartmentID
WHERE DH.EndDate IS NULL
    AND D.DepartmentID IN (12, 14)
GROUP BY ROLLUP(D.Name, E.JobTitle)
-- HAVING GROUPING_ID(D.Name, E.JobTitle) = 0; -- All titles
-- HAVING GROUPING_ID(D.Name, E.JobTitle) = 1; -- Group by Name;

Här är den ofiltrerade resultatuppsättningen.

Namn Titel Grupperingsnivå Antal anställda Namn
Dokumentkontroll Kontrollspecialist 0 2 Dokumentkontroll
Dokumentkontroll Dokumentkontrollassistent 0 2 Dokumentkontroll
Dokumentkontroll Dokumentkontrollhanterare 0 1 Dokumentkontroll
Dokumentkontroll NULL 1 5 Dokumentkontroll
Faciliteter och underhåll Administrativ assistent för anläggningar 0 1 Faciliteter och underhåll
Faciliteter och underhåll Fastighetschef 0 1 Faciliteter och underhåll
Faciliteter och underhåll Vaktmästare 0 4 Faciliteter och underhåll
Faciliteter och underhåll Underhållschef 0 1 Faciliteter och underhåll
Faciliteter och underhåll NULL 1 7 Faciliteter och underhåll
NULL NULL 3 12 NULL

Komplext exempel

Följande exempel använder GROUPING_ID() för att filtrera en resultatmängd som innehåller flera grupperingsnivåer efter grupperingsnivå. Liknande kod kan användas för att skapa en vy med flera grupperingsnivåer, samt en lagrad proprodur som anropar vyn genom att skicka en parameter som filtrerar vyn efter grupperingsnivå.

DECLARE @Grouping NVARCHAR(50);
DECLARE @GroupingLevel SMALLINT;

SET @Grouping = N'CountryRegionCode Total';

SELECT @GroupingLevel = (
    CASE @Grouping
        WHEN N'Grand Total' THEN 15
        WHEN N'SalesPerson Total' THEN 14
        WHEN N'Store Total' THEN 13
        WHEN N'Store SalesPerson Total' THEN 12
        WHEN N'CountryRegionCode Total' THEN 11
        WHEN N'Group Total' THEN 7
        ELSE N'Unknown'
    END
);

SELECT T.[Group],
    T.CountryRegionCode,
    S.Name AS N'Store',
    (
        SELECT P.FirstName + ' ' + P.LastName
        FROM Person.Person AS P
        WHERE P.BusinessEntityID = H.SalesPersonID
    ) AS N'Sales Person',
    SUM(TotalDue) AS N'TotalSold',
    CAST(GROUPING(T.[Group]) AS CHAR(1)) + CAST(GROUPING(T.CountryRegionCode) AS CHAR(1)) + CAST(GROUPING(S.Name) AS CHAR(1)) + CAST(GROUPING(H.SalesPersonID) AS CHAR(1)) AS N'GROUPING base-2',
    GROUPING_ID((T.[Group]), (T.CountryRegionCode), (S.Name), (H.SalesPersonID)) AS N'GROUPING_ID',
    CASE 
        WHEN GROUPING_ID((T.[Group]), (T.CountryRegionCode), (S.Name), (H.SalesPersonID)) = 15
            THEN N'Grand Total'
        WHEN GROUPING_ID((T.[Group]), (T.CountryRegionCode), (S.Name), (H.SalesPersonID)) = 14
            THEN N'SalesPerson Total'
        WHEN GROUPING_ID((T.[Group]), (T.CountryRegionCode), (S.Name), (H.SalesPersonID)) = 13
            THEN N'Store Total'
        WHEN GROUPING_ID((T.[Group]), (T.CountryRegionCode), (S.Name), (H.SalesPersonID)) = 12
            THEN N'Store SalesPerson Total'
        WHEN GROUPING_ID((T.[Group]), (T.CountryRegionCode), (S.Name), (H.SalesPersonID)) = 11
            THEN N'CountryRegionCode Total'
        WHEN GROUPING_ID((T.[Group]), (T.CountryRegionCode), (S.Name), (H.SalesPersonID)) = 7
            THEN N'Group Total'
        ELSE N'Error'
    END AS N'Level'
FROM Sales.Customer AS C
INNER JOIN Sales.Store AS S
    ON C.StoreID = S.BusinessEntityID
INNER JOIN Sales.SalesTerritory AS T
    ON C.TerritoryID = T.TerritoryID
INNER JOIN Sales.SalesOrderHeader AS H
    ON C.CustomerID = H.CustomerID
GROUP BY GROUPING SETS(
    (S.Name,H.SalesPersonID),
    (H.SalesPersonID), 
    (S.Name), 
    (T.[Group]),
    (T.CountryRegionCode),
    ()
)
HAVING GROUPING_ID(
    (T.[Group]),
    (T.CountryRegionCode),
    (S.Name),
    (H.SalesPersonID)
) = @GroupingLevel
ORDER BY
    GROUPING_ID(S.Name, H.SalesPersonID),
    GROUPING_ID(
        (T.[Group]),
        (T.CountryRegionCode),
        (S.Name),
        (H.SalesPersonID)
    ) ASC;

C. Använd GROUPING_ID() med ROLLUP och CUBE för att identifiera grupperingsnivåer

Koden i följande exempel visar att man använder GROUPING() för att beräkna kolumnen Bit Vector(base-2) . GROUPING_ID() används för att beräkna motsvarande Integer Equivalent kolumn. Kolumnordningen i GROUPING_ID() funktionen är motsatsen till kolumnordningen hos de kolumner som är sammanfogade av GROUPING() funktionen.

I dessa exempel GROUPING_ID() används för att skapa ett värde för varje rad i kolumnen Grouping Level för att identifiera nivån av gruppering. Grupperingsnivåer är inte alltid en på varandra följande lista av heltal som börjar med 1 (0, 1, 2, ... n).

Anmärkning

GROUPING och GROUPING_ID kan användas i en HAVING klausul för att filtrera en resultatmängd.

ROLLUP-exempel

I detta exempel visas inte alla grupperingsnivåer som de gör i följande CUBE exempel. Om ordningen på kolumnerna i ROLLUP listan ändras måste även nivåvärdena i Grouping Level kolumnen ändras.

SELECT DATEPART(yyyy, OrderDate) AS N'Year',
    DATEPART(mm, OrderDate) AS N'Month',
    DATEPART(dd, OrderDate) AS N'Day',
    SUM(TotalDue) AS N'Total Due',
    CAST(GROUPING(DATEPART(dd, OrderDate)) AS CHAR(1)) + CAST(GROUPING(DATEPART(mm, OrderDate)) AS CHAR(1)) + CAST(GROUPING(DATEPART(yyyy, OrderDate)) AS CHAR(1)) AS N'Bit Vector(base-2)',
    GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) AS N'Integer Equivalent',
    CASE 
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 0
            THEN N'Year Month Day'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 1
            THEN N'Year Month'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 2
            THEN N'not used'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 3
            THEN N'Year'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 4
            THEN N'not used'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 5
            THEN N'not used'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 6
            THEN N'not used'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 7
            THEN N'Grand Total'
        ELSE N'Error'
    END AS N'Grouping Level'
FROM Sales.SalesOrderHeader
WHERE DATEPART(yyyy, OrderDate) IN (N'2007', N'2008')
    AND DATEPART(mm, OrderDate) IN (1, 2)
    AND DATEPART(dd, OrderDate) IN (1, 2)
GROUP BY ROLLUP(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate))
ORDER BY GROUPING_ID(DATEPART(mm, OrderDate), DATEPART(yyyy, OrderDate), DATEPART(dd, OrderDate)),
    DATEPART(yyyy, OrderDate),
    DATEPART(mm, OrderDate),
    DATEPART(dd, OrderDate);

Här är en partiell resultatuppsättning.

År Månad Day Total förfallen Bitvektor (bas-2) Heltalsekvivalent Grupperingsnivå
2007 1 1 1497452.6066 000 0 År Månad Dag
2007 1 2 21772.3494 000 0 År Månad Dag
2007 2 1 2705653.5913 000 0 År Månad Dag
2007 2 2 21684.4068 000 0 År Månad Dag
2008 1 1 1908122.0967 000 0 År Månad Dag
2008 1 2 46458.0691 000 0 År Månad Dag
2008 2 1 3108771.9729 000 0 År Månad Dag
2008 2 2 54598.5488 000 0 År Månad Dag
2007 1 NULL 1519224.956 100 1 Årsmånaden
2007 2 NULL 2727337.9981 100 1 Årsmånaden
2008 1 NULL 1954580.1658 100 1 Årsmånaden
2008 2 NULL 3163370.5217 100 1 Årsmånaden
2007 NULL NULL 4246562.9541 110 3 År
2008 NULL NULL 5117950.6875 110 3 År
NULL NULL NULL 9364513.6416 111 7 Totalsumma

CUBE-exempel

I detta exempel GROUPING_ID() används funktionen för att skapa ett värde för varje rad i kolumnen Grouping Level för att identifiera nivån på grupperingen.

Till skillnad från ROLLUP i det föregående exemplet CUBE ger den alla grupperingsnivåer. Om ordningen på kolumnerna i CUBE listan ändras måste även nivåvärdena i Grouping Level kolumnen ändras.

SELECT DATEPART(yyyy, OrderDate) AS N'Year',
    DATEPART(mm, OrderDate) AS N'Month',
    DATEPART(dd, OrderDate) AS N'Day',
    SUM(TotalDue) AS N'Total Due',
    CAST(GROUPING(DATEPART(dd, OrderDate)) AS CHAR(1)) + CAST(GROUPING(DATEPART(mm, OrderDate)) AS CHAR(1)) + CAST(GROUPING(DATEPART(yyyy, OrderDate)) AS CHAR(1)) AS N'Bit Vector(base-2)',
    GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) AS N'Integer Equivalent',
    CASE 
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 0
            THEN N'Year Month Day'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 1
            THEN N'Year Month'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 2
            THEN N'Year Day'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 3
            THEN N'Year'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 4
            THEN N'Month Day'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 5
            THEN N'Month'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 6
            THEN N'Day'
        WHEN GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)) = 7
            THEN N'Grand Total'
        ELSE N'Error'
    END AS N'Grouping Level'
FROM Sales.SalesOrderHeader
WHERE DATEPART(yyyy, OrderDate) IN (N'2007', N'2008')
    AND DATEPART(mm, OrderDate) IN (1, 2)
    AND DATEPART(dd, OrderDate) IN (1, 2)
GROUP BY CUBE(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate))
ORDER BY GROUPING_ID(DATEPART(yyyy, OrderDate), DATEPART(mm, OrderDate), DATEPART(dd, OrderDate)),
    DATEPART(yyyy, OrderDate),
    DATEPART(mm, OrderDate),
    DATEPART(dd, OrderDate);

Här är en partiell resultatuppsättning.

År Månad Day Total förfallen Bitvektor (bas-2) Heltalsekvivalent Grupperingsnivå
2007 1 1 1497452.6066 000 0 År Månad Dag
2007 1 2 21772.3494 000 0 År Månad Dag
2007 2 1 2705653.5913 000 0 År Månad Dag
2007 2 2 21684.4068 000 0 År Månad Dag
2008 1 1 1908122.0967 000 0 År Månad Dag
2008 1 2 46458.0691 000 0 År Månad Dag
2008 2 1 3108771.9729 000 0 År Månad Dag
2008 2 2 54598.5488 000 0 År Månad Dag
2007 1 NULL 1519224.956 100 1 Årsmånaden
2007 2 NULL 2727337.9981 100 1 Årsmånaden
2008 1 NULL 1954580.1658 100 1 Årsmånaden
2008 2 NULL 3163370.5217 100 1 Årsmånaden
2007 NULL 1 4203106.1979 010 2 Årets dag
2007 NULL 2 43456.7562 010 2 Årets dag
2008 NULL 1 5016894.0696 010 2 Årets dag
2008 NULL 2 101056.6179 010 2 Årets dag
2007 NULL NULL 4246562.9541 110 3 År
2008 NULL NULL 5117950.6875 110 3 År
NULL 1 1 3405574.7033 001 4 Månadsdagen
NULL 1 2 68230.4185 001 4 Månadsdagen
NULL 2 1 5814425.5642 001 4 Månadsdagen
NULL 2 2 76282.9556 001 4 Månadsdagen
NULL 1 NULL 3473805.1218 101 5 Månad
NULL 2 NULL 5890708.5198 101 5 Månad
NULL NULL 1 9220000.2675 011 6 Day
NULL NULL 2 144513.3741 011 6 Day
NULL NULL NULL 9364513.6416 111 7 Totalsumma