GROUPING_ID (Transact-SQL)
Ist eine Funktion, die die Ebene der Gruppierung berechnet. GROUPING_ID kann in der SELECT-<Auswahlliste>, der HAVING- oder der ORDER BY-Klausel nur verwendet werden, wenn GROUP BY angegeben wurde.
Syntax
GROUPING_ID ( <column_expression>[ ,...n ] )
Rückgabetyp
int
Hinweise
Der GROUPING_ID <Spaltenausdruck> muss genau mit dem Ausdruck in der GROUP BY-Liste übereinstimmen. Wenn Sie beispielsweise nach DATEPART gruppieren (yyyy, <column name>), verwenden Sie GROUPING_ID (DATEPART (yyyy, <column name>)). Oder wenn Sie nach <column name> gruppieren, verwenden Sie GROUPING_ID (<column name>).
Vergleichen von GROUPING_ID () mit GROUPING ()
GROUPING_ID (<Spaltenausdruck> [ ,...n ]) ]) fügt die Entsprechung der Rückgabe von GROUPING (<Spaltenausdruck>) für jede Spalte in seiner Spaltenliste in jeder Ausgabezeile als Zeichenfolge aus Einsen und Nullen ein. GROUPING_ID interpretiert diese Zeichenfolge als Basis-2-Nummer und gibt die entsprechende ganze Zahl zurück. Sehen Sie sich beispielsweise folgende Anweisung an: SELECT a, b, c, SUM(d),GROUPING_ID(a,b,c)FROM T GROUP BY <group by list>. Die folgende Tabelle zeigt die Ein- und Ausgabewerte für GROUPING_ID ().
Aggregierte Spalten |
GROUPING_ID (a, b, c) Eingabe = GROUPING(a) + GROUPING(b) + GROUPING(c) |
GROUPING_ID () Ausgabe |
---|---|---|
a |
100 |
4 |
b |
010 |
2 |
c |
001 |
1 |
ab |
110 |
6 |
ac |
101 |
5 |
bc |
011 |
3 |
abc |
111 |
7 |
Technische Definition von GROUPING_ID ()
Jedes GROUPING_ID-Argument muss ein Element der GROUP BY-Liste sein. GROUPING_ID () gibt eine integer-Bitmap zurück, deren niedrigstes N-Bit hervorgehoben sein kann. Ein hervorgehobenes bit gibt an, dass das zugehörige Argument keine Gruppierungsspalte für die entsprechende Ausgabezeile ist. Das niedrigstebit in der Reihenfolge entspricht Argument N, und das N-1tebit der Reihenfolge entspricht Argument 1.
GROUPING_ID ()-Entsprechungen
Für eine einzelne Gruppierungsabfrage entspricht GROUPING (<Spaltenausdruck>) GROUPING_ID (<Spaltenausdruck>), und beide geben 0 zurück.
Beispielsweise sind die folgenden Anweisungen äquivalent:
|
|
Beispiele
A. Verwenden von GROUPING_ID zur Identifizierung von Gruppierungsebenen
Das folgende Beispiel gibt die Anzahl der Mitarbeiter nach Name und Title sowie Name, und Unternehmen insgesamt zurück. GROUPING_ID() wird verwendet, um einen Wert für jede Zeile in der Title-Spalte zu erstellen, die die Aggregationsebene angibt.
USE AdventureWorks;
GO
SELECT D.Name
,CASE
WHEN GROUPING_ID(D.Name, E.Title) = 0 THEN E.Title
WHEN GROUPING_ID(D.Name, E.Title) = 1 THEN N'Total: ' + D.Name
WHEN GROUPING_ID(D.Name, E.Title) = 3 THEN N'Company Total:'
ELSE N'Unknown'
END AS N'Title'
,COUNT(E.EmployeeID) AS N'Employee Count'
FROM HumanResources.Employee E
INNER JOIN HumanResources.EmployeeDepartmentHistory DH
ON E.EmployeeID = DH.EmployeeID
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.Title);
B. Verwenden von GROUPING_ID zum Filtern eines Resultsets
Einfaches Beispiel
Um nur die Zeilen zurückzugeben, die die Anzahl der Mitarbeiter nach Titel enthalten, entfernen Sie im folgenden Code die Kommentierungszeichen von HAVING GROUPING_ID(D.Name, E.Title); = 0. Um nur die Zeilen zurückzugeben, die die Anzahl der Mitarbeiter nach Abteilung enthalten, entfernen Sie die Kommentierungszeichen von HAVING GROUPING_ID(D.Name, E.Title) = 1;.
USE AdventureWorks;
GO
SELECT D.Name
,E.Title
,GROUPING_ID(D.Name, E.Title) AS 'Grouping Level'
,COUNT(E.EmployeeID) AS N'Employee Count'
FROM HumanResources.Employee E
INNER JOIN HumanResources.EmployeeDepartmentHistory DH
ON E.EmployeeID = DH.EmployeeID
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.Title)
--HAVING GROUPING_ID(D.Name, E.Title) = 0; --All titles
--HAVING GROUPING_ID(D.Name, E.Title) = 1; --Group by Name
Das ungefilterte Resultset sieht folgendermaßen aus.
Name |
Title |
Gruppierungsebene |
Anzahl der Mitarbeiter |
Name |
---|---|---|---|---|
Dokumentsteuerung |
Steuerungsspezialist |
0 |
2 |
Dokumentsteuerung |
Dokumentsteuerung |
Dokumentsteuerungs-Assistent |
0 |
2 |
Dokumentsteuerung |
Dokumentsteuerung |
Dokumentsteuerungs-Manager |
0 |
1 |
Dokumentsteuerung |
Dokumentsteuerung |
NULL |
1 |
5 |
Dokumentsteuerung |
Einrichtungen und Wartung |
Einrichtungen-Verwaltungs-Assistent |
0 |
1 |
Einrichtungen und Wartung |
Einrichtungen und Wartung |
Einrichtungs-Manager |
0 |
1 |
Einrichtungen und Wartung |
Einrichtungen und Wartung |
Pförtner |
0 |
4 |
Einrichtungen und Wartung |
Einrichtungen und Wartung |
Wartungsleiter |
0 |
1 |
Einrichtungen und Wartung |
Einrichtungen und Wartung |
NULL |
1 |
7 |
Einrichtungen und Wartung |
NULL |
NULL |
3 |
12 |
NULL |
Komplexes Beispiel
Im folgenden Beispiel wird GROUPING_ID() dazu verwendet, ein Resultset mit mehreren Gruppierungsebenen nach Gruppierungsebene zu filtern. Der gleiche Code kann verwendet werden, um eine Sicht mit mehreren Gruppierungsebenen zu erstellen sowie eine gespeicherte Prozedur, die die Sicht aufruft, indem ein Parameter übergeben wird, der die Sicht nach Gruppierungsebene filtert.
USE AdventureWorks;
GO
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 C.FirstName + ' ' + C.LastName
FROM Person.Contact C
WHERE C.ContactId = 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 C
INNER JOIN Sales.Store S
ON C.CustomerID = S.CustomerID
INNER JOIN Sales.SalesTerritory T
ON C.TerritoryID = T.TerritoryID
INNER JOIN Sales.SalesOrderHeader H
ON S.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. Verwenden von GROUPING_ID () mit ROLLUP und CUBE, um Gruppierungsebenen zu ermitteln
Der Code im folgenden Beispiel zeigt die Verwendung von GROUPING() zur Berechnung der Bit Vector(base-2)-Spalte. GROUPING_ID() wird zur Berechnung der entsprechenden Integer Equivalent-Spalte verwendet. Die Spaltenreihenfolge in der GROUPING_ID()-Funktion ist die umgekehrte Reihenfolge der Spalten, die durch die GROUPING()-Funktion verkettet sind.
In diesen Beispielen wird GROUPING_ID() verwendet, um einen Wert für jede Zeile in der Grouping Level-Spalte zu erstellen, um die Gruppierungsebene zu ermitteln. Gruppierungsebenen sind nicht immer eine aufeinander folgende Liste von ganzen Zahlen, die mit 1 (0, 1, 2,...n) beginnen.
Hinweis |
---|
GROUPING und GROUPING_ID können in einer HAVING-Klausel verwendet werden, um ein Resultset zu filtern. |
ROLLUP-Beispiel
In diesem Beispiel werden die Gruppierungsebenen nicht so angezeigt, wie sie im folgenden CUBE-Beispiel dargestellt werden. Wenn die Reihenfolge der Spalten in der ROLLUP-Liste geändert wird, müssen auch die Ebenenwerte in der Grouping Level-Spalte geändert werden.
USE AdventureWorks;
GO
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'2003',N'2004')
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);
Dies ist ein Auszug aus dem Resultset.
Year |
Month |
Day |
Total Due |
Bit-Vektor (Basis-2) |
Ganzzahlige Entsprechung |
Gruppierungsebene |
---|---|---|---|---|---|---|
2003 |
1 |
1 |
1762381 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
1 |
2 |
21772.35 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
2 |
1 |
3185233 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
2 |
2 |
21684.41 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
1 |
1 |
2239208 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
1 |
2 |
46458.07 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
2 |
1 |
3653194 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
2 |
2 |
54598.55 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
1 |
NULL |
1784153 |
100 |
1 |
Jahr und Monat |
2003 |
2 |
NULL |
3206917 |
100 |
1 |
Jahr und Monat |
2004 |
1 |
NULL |
2285666 |
100 |
1 |
Jahr und Monat |
2004 |
2 |
NULL |
3707793 |
100 |
1 |
Jahr und Monat |
2003 |
NULL |
NULL |
4991070 |
110 |
3 |
Year |
2004 |
NULL |
NULL |
5993459 |
110 |
3 |
Year |
NULL |
NULL |
NULL |
10984529 |
111 |
7 |
Gesamtsumme |
CUBE-Beispiel
In diesen Beispielen wird die GROUPING_ID()-Funktion verwendet, um einen Wert für jede Zeile in der Grouping Level-Spalte zu erstellen, um die Gruppierungsebene zu ermitteln.
Im Gegensatz zu ROLLUP im vorherigen Beispiel gibt CUBE alle Gruppierungsebenen aus. Wenn die Reihenfolge der Spalten in der CUBE-Liste geändert wird, müssen auch die Ebenenwerte in der Grouping Level-Spalte geändert werden.
USE AdventureWorks;
GO
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'2003',N'2004')
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);
Dies ist ein Auszug aus dem Resultset.
Year |
Month |
Day |
Total Due |
Bit-Vektor (Basis-2) |
Ganzzahlige Entsprechung |
Gruppierungsebene |
---|---|---|---|---|---|---|
2003 |
1 |
1 |
1762381 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
1 |
2 |
21772.35 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
2 |
1 |
3185233 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
2 |
2 |
21684.41 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
1 |
1 |
2239208 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
1 |
2 |
46458.07 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
2 |
1 |
3653194 |
000 |
0 |
Jahr, Monat, Tag |
2004 |
2 |
2 |
54598.55 |
000 |
0 |
Jahr, Monat, Tag |
2003 |
1 |
NULL |
1784153 |
100 |
1 |
Jahr und Monat |
2003 |
2 |
NULL |
3206917 |
100 |
1 |
Jahr und Monat |
2004 |
1 |
NULL |
2285666 |
100 |
1 |
Jahr und Monat |
2004 |
2 |
NULL |
3707793 |
100 |
1 |
Jahr und Monat |
2003 |
NULL |
1 |
4947613 |
010 |
2 |
Jahr und Tag |
2003 |
NULL |
2 |
43456.76 |
010 |
2 |
Jahr und Tag |
2004 |
NULL |
1 |
5892402 |
010 |
2 |
Jahr und Tag |
2004 |
NULL |
2 |
101056.6 |
010 |
2 |
Jahr und Tag |
2003 |
NULL |
NULL |
4991070 |
110 |
3 |
Year |
2004 |
NULL |
NULL |
5993459 |
110 |
3 |
Year |
NULL |
1 |
1 |
4001589 |
001 |
4 |
Monat und Tag |
NULL |
1 |
2 |
68230.42 |
001 |
4 |
Monat und Tag |
NULL |
2 |
1 |
6838427 |
001 |
4 |
Monat und Tag |
NULL |
2 |
2 |
76282.96 |
001 |
4 |
Monat und Tag |
NULL |
1 |
NULL |
4069819 |
101 |
5 |
Month |
NULL |
2 |
NULL |
6914710 |
101 |
5 |
Month |
NULL |
NULL |
1 |
10840016 |
011 |
6 |
Day |
NULL |
NULL |
2 |
144513.4 |
011 |
6 |
Day |
NULL |
NULL |
NULL |
10984529 |
111 |
7 |
Gesamtsumme |