Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
gäller för:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
Analytics Platform System (PDW)
SQL-analysslutpunkt i Microsoft Fabric
Warehouse i Microsoft Fabric
SQL-databas i Microsoft Fabric
Anger en tillfällig namngiven resultatuppsättning, som kallas för ett gemensamt tabelluttryck (CTE). Detta härleds från en enkel fråga och definieras inom körningsomfånget för en enda SELECT
, INSERT
, UPDATE
, MERGE
eller DELETE
-instruktion. Den här satsen kan också användas i en -instruktion som en CREATE VIEW
del av dess definierande SELECT
instruktion. Ett vanligt tabelluttryck kan innehålla referenser till sig själv. Detta kallas för ett rekursivt vanligt tabelluttryck.
Transact-SQL syntaxkonventioner
Syntax
[ WITH <common_table_expression> [ , ...n ] ]
<common_table_expression>::=
expression_name [ ( column_name [ , ...n ] ) ]
AS
( CTE_query_definition )
Argumentpunkter
expression_name
En giltig identifierare för det vanliga tabelluttrycket.
expression_name måste skilja sig från namnet på andra vanliga tabelluttryck som definierats i samma WITH <common_table_expression>
sats, men expression_name kan vara samma som namnet på en bastabell eller vy. Alla referenser till expression_name i frågan använder det gemensamma tabelluttrycket och inte basobjektet.
column_name
Anger ett kolumnnamn i det gemensamma tabelluttrycket. Dubblettnamn inom en enda CTE-definition tillåts inte. Antalet kolumnnamn som anges måste matcha antalet kolumner i resultatuppsättningen för CTE_query_definition. Listan med kolumnnamn är endast valfri om distinkta namn för alla resulterande kolumner anges i frågedefinitionen.
CTE_query_definition
Anger en SELECT
instruktion vars resultatuppsättning fyller det gemensamma tabelluttrycket. Instruktionen SELECT
för CTE_query_definition måste uppfylla samma krav som för att skapa en vy, förutom att en CTE inte kan definiera en annan CTE. Mer information finns i avsnittet Anmärkningar och SKAPA VY.
Om fler än en CTE_query_definition har definierats måste frågedefinitionerna kopplas av någon av dessa uppsättningsoperatorer: UNION ALL
, UNION
, EXCEPT
eller INTERSECT
.
Användningsriktlinjer
Riktlinjer för icke-kursiva vanliga tabelluttryck
Anmärkning
Följande riktlinjer gäller för icke-aktuella vanliga tabelluttryck. Riktlinjer som gäller för rekursiva vanliga tabelluttryck finns i Riktlinjer för rekursiva vanliga tabelluttryck.
En CTE måste följas av en enda SELECT
, INSERT
, UPDATE
, MERGE
eller DELETE
-instruktion som refererar till vissa eller alla CTE-kolumner. En CTE kan också anges i en -instruktion som en CREATE VIEW
del av den definierande SELECT
instruktionen för vyn.
Flera CTE-frågedefinitioner kan definieras i en icke-cursiv CTE. Definitionerna måste kombineras av någon av dessa uppsättningsoperatorer: UNION ALL
, UNION
, INTERSECT
, eller EXCEPT
.
En CTE kan referera till sig själv och tidigare definierade CTE:er i samma WITH
sats. Vidarebefordran av hänvisningar tillåts inte.
Det är inte tillåtet att ange fler än en WITH
sats i en CTE. Om en CTE_query_definition till exempel innehåller en underfråga kan den underfrågan inte innehålla en kapslad sats WITH
som definierar en annan CTE.
Mer information om kapslade CTE:er i Microsoft Fabric finns i Kapslat common table expression (CTE) i Fabric-datalager (Transact-SQL).
Frågeresultat från vanliga tabelluttryck materialiseras inte. Varje yttre referens till den namngivna resultatuppsättningen kräver att den definierade frågan körs igen. Överväg att använda ett tillfälligt objekt i stället för frågor som kräver flera referenser till den namngivna resultatuppsättningen.
Du kan inte köra en lagrad procedur i ett gemensamt tabelluttryck.
Följande satser kan inte användas i CTE_query_definition:
-
ORDER BY
(förutom när enTOP
eller-satsOFFSET/FETCH
anges) INTO
-
OPTION
sats med frågetips 1 FOR BROWSE
1 Satsen OPTION
kan inte användas i en CTE-definition. Den kan bara användas i den yttersta SELECT
instruktionen.
När en CTE används i en -sats som är en del av en batch måste -instruktionen innan den följas av ett semikolon.
En fråga som refererar till en CTE kan användas för att definiera en markör.
Tabeller på fjärrservrar kan refereras i CTE.
När du kör en CTE kan alla tips som refererar till en CTE komma i konflikt med andra tips som identifieras när CTE kommer åt sina underliggande tabeller, på samma sätt som tips som refererar till vyer i frågor. När detta inträffar returnerar frågan ett fel.
Riktlinjer för rekursiva vanliga tabelluttryck
Anmärkning
Följande riktlinjer gäller för att definiera ett rekursivt gemensamt tabelluttryck. Riktlinjer som gäller för icke-aktuella CTE:er finns i Riktlinjer för icke-kursiva vanliga tabelluttryck.
Den rekursiva CTE-definitionen måste innehålla minst två CTE-frågedefinitioner, en fästpunktsmedlem och en rekursiv medlem. Flera fästpunktsmedlemmar och rekursiva medlemmar kan definieras. Alla frågedefinitioner för fästpunktsmedlemmar måste dock placeras före den första rekursiva medlemsdefinitionen. Alla CTE-frågedefinitioner är fästpunktsmedlemmar om de inte refererar till själva CTE.
Fästpunktsmedlemmar måste kombineras av någon av dessa uppsättningsoperatorer: UNION ALL
, UNION
, INTERSECT
eller EXCEPT
.
UNION ALL
är den enda uppsättningsoperatorn som tillåts mellan den sista fästpunktsmedlemmen och den första rekursiva medlemmen och när flera rekursiva medlemmar kombineras.
Antalet kolumner i fästpunkten och rekursiva medlemmar måste vara detsamma.
Datatypen för en kolumn i den rekursiva medlemmen måste vara samma som datatypen för motsvarande kolumn i fästpunktsmedlemmen.
FROM-satsen för en rekursiv medlem får bara referera en gång till CTE-expression_name.
Följande objekt tillåts inte i CTE_query_definition för en rekursiv medlem:
SELECT DISTINCT
GROUP BY
-
PIVOT
1 HAVING
- Scalar-aggregering
TOP
-
LEFT
,RIGHT
,OUTER JOIN
(INNER JOIN
tillåts) - Underfrågor
- Ett tips som tillämpas på en rekursiv referens till en CTE i en CTE_query_definition.
1 När databasens kompatibilitetsnivå är 110 eller högre. Se Icke-bakåtkompatibla ändringar av databasmotorfunktioner i SQL Server 2016.
Följande riktlinjer gäller för användning av ett rekursivt gemensamt tabelluttryck:
Alla kolumner som returneras av den rekursiva CTE:en är nullbara oavsett om kolumnerna som returneras av de deltagande
SELECT
uttrycken är nulla.En felaktigt sammansatt rekursiv CTE kan orsaka en oändlig loop. Om frågedefinitionen rekursiv medlem till exempel returnerar samma värden för både överordnade och underordnade kolumner skapas en oändlig loop. För att förhindra en oändlig loop kan du begränsa antalet rekursionsnivåer som tillåts för en viss instruktion med hjälp av tipset
MAXRECURSION
och ett värde mellan0
och32767
i -instruktionenOPTION
i instruktionenINSERT
,UPDATE
,DELETE
ellerSELECT
. På så sätt kan du styra körningen av -instruktionen tills du löser kodproblemet som skapar loopen. Standardvärdet för hela servern är 100. När 0 har angetts tillämpas ingen gräns. Endast ettMAXRECURSION
värde kan anges per instruktion. Mer information finns i Frågetips.En vy som innehåller ett rekursivt vanligt tabelluttryck kan inte användas för att uppdatera data.
Markörer kan definieras för frågor med hjälp av CTE:er. CTE är det select_statement argument som definierar markörens resultatuppsättning. Endast snabbsnabb framåtriktade och statiska markörer (ögonblicksbilder) tillåts för rekursiva CTE:er. Om en annan markörtyp anges i en rekursiv CTE konverteras markörtypen till statisk.
Tabeller på fjärrservrar kan refereras i CTE. Om fjärrservern refereras till i den rekursiva medlemmen i CTE skapas en spool för varje fjärrtabell så att tabellerna kan nås upprepade gånger lokalt. Om det är en CTE-fråga visas Index Spool/Lazy Spools i frågeplanen och har ytterligare
WITH STACK
predikat. Detta är ett sätt att bekräfta korrekt rekursion.Analys- och aggregeringsfunktioner i den rekursiva delen av CTE tillämpas på uppsättningen för den aktuella rekursionsnivån och inte på uppsättningen för CTE. Funktioner som fungerar endast på den delmängd av data som
ROW_NUMBER
skickas till dem av den aktuella rekursionsnivån och inte hela uppsättningen data som skickas till den rekursiva delen av CTE. Mer information finns i exempel I. Använd analysfunktioner i en rekursiv CTE som följer.
Vanliga tabelluttryck i Azure Synapse Analytics and Analytics Platform System (PDW)
Den aktuella implementeringen av CTE:er i Azure Synapse Analytics and Analytics Platform System (PDW) har följande funktioner och krav:
En CTE kan anges i en
SELECT
-instruktion.En CTE kan anges i en
CREATE VIEW
-instruktion.En CTE kan anges i en
CREATE TABLE AS SELECT
(CTAS)-instruktion.En CTE kan anges i en
CREATE REMOTE TABLE AS SELECT
(CRTAS)-instruktion.En CTE kan anges i en
CREATE EXTERNAL TABLE AS SELECT
(CETAS)-instruktion.En fjärrtabell kan refereras från en CTE.
En extern tabell kan refereras från en CTE.
Flera CTE-frågedefinitioner kan definieras i en CTE.
En CTE kan följas av
SELECT
,INSERT
,UPDATE
,DELETE
ellerMERGE
-instruktioner.Ett vanligt tabelluttryck som innehåller referenser till sig själv (ett rekursivt vanligt tabelluttryck) stöds inte.
Det är inte tillåtet att ange fler än en
WITH
sats i en CTE. Om en CTE-frågedefinition till exempel innehåller en underfråga kan den underfrågan inte innehålla en kapslad satsWITH
som definierar en annan CTE.Det
ORDER BY
går inte att använda en sats i CTE_query_definition, förutom när enTOP
sats har angetts.När en CTE används i en -sats som är en del av en batch måste -instruktionen innan den följas av ett semikolon.
När de används i instruktioner som utarbetats av
sp_prepare
beter sig CTE på samma sätt som andraSELECT
instruktioner i APS PDW. Men om CTE:er används som en del av CETAS som förberetts avsp_prepare
kan beteendet skjutas upp från SQL Server och andra APS PDW-instruktioner på grund av hur bindningen implementeras försp_prepare
. OmSELECT
det refererar till CTE använder en fel kolumn som inte finns i CTE,sp_prepare
passerar utan att identifiera felet, men felet utlöses undersp_execute
i stället.
Exempel
A. Skapa ett vanligt tabelluttryck
I följande exempel visas det totala antalet försäljningsorder per år för varje säljare på Adventure Works Cycles.
-- Define the CTE expression name and column list.
WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
AS
-- Define the CTE query.
(
SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
)
-- Define the outer query referencing the CTE name.
SELECT SalesPersonID,
COUNT(SalesOrderID) AS TotalSales,
SalesYear
FROM Sales_CTE
GROUP BY SalesYear, SalesPersonID
ORDER BY SalesPersonID, SalesYear;
B. Använd ett vanligt tabelluttryck för att begränsa antal och rapportgenomsnitt
I följande exempel visas det genomsnittliga antalet försäljningsorder för alla år för säljrepresentanterna.
WITH Sales_CTE (SalesPersonID, NumberOfOrders)
AS
(
SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID
)
SELECT AVG(NumberOfOrders) AS "Average Sales Per Person"
FROM Sales_CTE;
C. Använda flera CTE-definitioner i en enda fråga
I följande exempel visas hur du definierar mer än en CTE i en enda fråga. Ett kommatecken används för att avgränsa CTE-frågedefinitionerna. Funktionen FORMAT
, som används för att visa de monetära beloppen i valutaformat, introducerades i SQL Server 2012 (11.x).
WITH Sales_CTE (SalesPersonID, TotalSales, SalesYear)
AS
-- Define the first CTE query.
(
SELECT SalesPersonID,
SUM(TotalDue) AS TotalSales,
YEAR(OrderDate) AS SalesYear
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID, YEAR(OrderDate)
), -- Use a comma to separate multiple CTE definitions.
-- Define the second CTE query, which returns sales quota data by year for each sales person.
Sales_Quota_CTE (BusinessEntityID, SalesQuota, SalesQuotaYear)
AS
(
SELECT BusinessEntityID,
SUM(SalesQuota) AS SalesQuota,
YEAR(QuotaDate) AS SalesQuotaYear
FROM Sales.SalesPersonQuotaHistory
GROUP BY BusinessEntityID, YEAR(QuotaDate)
)
-- Define the outer query by referencing columns from both CTEs.
SELECT SalesPersonID,
SalesYear,
FORMAT(TotalSales, 'C', 'en-us') AS TotalSales,
SalesQuotaYear,
FORMAT(SalesQuota, 'C', 'en-us') AS SalesQuota,
FORMAT(TotalSales - SalesQuota, 'C', 'en-us') AS Amt_Above_or_Below_Quota
FROM Sales_CTE
INNER JOIN Sales_Quota_CTE
ON Sales_Quota_CTE.BusinessEntityID = Sales_CTE.SalesPersonID
AND Sales_CTE.SalesYear = Sales_Quota_CTE.SalesQuotaYear
ORDER BY SalesPersonID, SalesYear;
Här är en partiell resultatuppsättning.
SalesPersonID SalesYear TotalSales SalesQuotaYear SalesQuota Amt_Above_or_Below_Quota
------------- --------- ----------- -------------- ---------- ----------------------------------
274 2005 $32,567.92 2005 $35,000.00 ($2,432.08)
274 2006 $406,620.07 2006 $455,000.00 ($48,379.93)
274 2007 $515,622.91 2007 $544,000.00 ($28,377.09)
274 2008 $281,123.55 2008 $271,000.00 $10,123.55
D. Använd ett rekursivt vanligt tabelluttryck för att visa flera rekursionsnivåer
I följande exempel visas den hierarkiska listan över chefer och de anställda som rapporterar till dem. Exemplet börjar med att skapa och fylla i dbo.MyEmployees
tabellen.
-- Create an Employee table.
CREATE TABLE dbo.MyEmployees
(
EmployeeID SMALLINT NOT NULL,
FirstName NVARCHAR (30) NOT NULL,
LastName NVARCHAR (40) NOT NULL,
Title NVARCHAR (50) NOT NULL,
DeptID SMALLINT NOT NULL,
ManagerID SMALLINT NULL,
CONSTRAINT PK_EmployeeID PRIMARY KEY CLUSTERED (EmployeeID ASC),
CONSTRAINT FK_MyEmployees_ManagerID_EmployeeID FOREIGN KEY (ManagerID) REFERENCES dbo.MyEmployees (EmployeeID)
);
-- Populate the table with values.
INSERT INTO dbo.MyEmployees VALUES
(1, N'Ken', N'Sánchez', N'Chief Executive Officer', 16, NULL),
(273, N'Brian', N'Welcker', N'Vice President of Sales', 3, 1),
(274, N'Stephen', N'Jiang', N'North American Sales Manager', 3, 273),
(275, N'Michael', N'Blythe', N'Sales Representative', 3, 274),
(276, N'Linda', N'Mitchell', N'Sales Representative', 3, 274),
(285, N'Syed', N'Abbas', N'Pacific Sales Manager', 3, 273),
(286, N'Lynn', N'Tsoflias', N'Sales Representative', 3, 285),
(16, N'David', N'Bradley', N'Marketing Manager', 4, 273),
(23, N'Mary', N'Gibson', N'Marketing Specialist', 4, 16);
WITH DirectReports (ManagerID, EmployeeID, Title, EmployeeLevel) AS
(
SELECT ManagerID, EmployeeID, Title, 0 AS EmployeeLevel
FROM dbo.MyEmployees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.ManagerID, e.EmployeeID, e.Title, EmployeeLevel + 1
FROM dbo.MyEmployees AS e
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
SELECT ManagerID, EmployeeID, Title, EmployeeLevel
FROM DirectReports
ORDER BY ManagerID;
Använd ett rekursivt vanligt tabelluttryck för att visa två rekursionsnivåer
I följande exempel visas chefer och anställda som rapporterar till dem. Antalet returnerade nivåer är begränsat till två.
WITH DirectReports (ManagerID, EmployeeID, Title, EmployeeLevel) AS
(
SELECT ManagerID, EmployeeID, Title, 0 AS EmployeeLevel
FROM dbo.MyEmployees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.ManagerID, e.EmployeeID, e.Title, EmployeeLevel + 1
FROM dbo.MyEmployees AS e
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
SELECT ManagerID, EmployeeID, Title, EmployeeLevel
FROM DirectReports
WHERE EmployeeLevel <= 2;
Använd ett rekursivt vanligt tabelluttryck för att visa en hierarkisk lista
I följande exempel läggs namnen på chefen och anställda och deras respektive titlar till. Hierarkin för chefer och anställda betonas dessutom genom att dra in varje nivå.
WITH DirectReports (Name, Title, EmployeeID, EmployeeLevel, Sort) AS
(
SELECT CONVERT (VARCHAR (255), e.FirstName + ' ' + e.LastName),
e.Title,
e.EmployeeID,
1,
CONVERT (VARCHAR (255), e.FirstName + ' ' + e.LastName)
FROM dbo.MyEmployees AS e
WHERE e.ManagerID IS NULL
UNION ALL
SELECT CONVERT (VARCHAR (255), REPLICATE('| ', EmployeeLevel) + e.FirstName + ' ' + e.LastName),
e.Title,
e.EmployeeID,
EmployeeLevel + 1,
CONVERT (VARCHAR (255), RTRIM(Sort) + '| ' + FirstName + ' ' + LastName)
FROM dbo.MyEmployees AS e
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
SELECT EmployeeID, Name, Title, EmployeeLevel
FROM DirectReports
ORDER BY Sort;
Använd MAXRECURSION för att avbryta en instruktion
MAXRECURSION
kan användas för att förhindra att en dåligt utformad rekursiv CTE kommer in i en oändlig loop. I följande exempel skapas avsiktligt en oändlig loop och MAXRECURSION
tips används för att begränsa antalet rekursionsnivåer till två.
--Creates an infinite loop
WITH cte (EmployeeID, ManagerID, Title) AS
(
SELECT EmployeeID, ManagerID, Title
FROM dbo.MyEmployees
WHERE ManagerID IS NOT NULL
UNION ALL
SELECT cte.EmployeeID, cte.ManagerID, cte.Title
FROM cte
INNER JOIN dbo.MyEmployees AS e
ON cte.ManagerID = e.EmployeeID
)
--Uses MAXRECURSION to limit the recursive levels to 2
SELECT EmployeeID, ManagerID, Title
FROM cte
OPTION (MAXRECURSION 2);
När kodfelet har korrigerats krävs inte längre MAXRECURSION
. I följande exempel visas den korrigerade koden.
WITH cte (EmployeeID, ManagerID, Title) AS
(
SELECT EmployeeID, ManagerID, Title
FROM dbo.MyEmployees
WHERE ManagerID IS NOT NULL
UNION ALL
SELECT e.EmployeeID, e.ManagerID, e.Title
FROM dbo.MyEmployees AS e
INNER JOIN cte
ON e.ManagerID = cte.EmployeeID
)
SELECT EmployeeID, ManagerID, Title
FROM cte;
E. Använd ett vanligt tabelluttryck för att selektivt gå igenom en rekursiv relation i en SELECT-instruktion
I följande exempel visas hierarkin för produktsammansättningar och komponenter som krävs för att bygga cykeln för ProductAssemblyID = 800
.
USE AdventureWorks2022;
GO
WITH Parts (AssemblyID, ComponentID, PerAssemblyQty, EndDate, ComponentLevel) AS
(
SELECT b.ProductAssemblyID,
b.ComponentID,
b.PerAssemblyQty,
b.EndDate,
0 AS ComponentLevel
FROM Production.BillOfMaterials AS b
WHERE b.ProductAssemblyID = 800
AND b.EndDate IS NULL
UNION ALL
SELECT bom.ProductAssemblyID,
bom.ComponentID,
p.PerAssemblyQty,
bom.EndDate,
ComponentLevel + 1
FROM Production.BillOfMaterials AS bom
INNER JOIN Parts AS p
ON bom.ProductAssemblyID = p.ComponentID
AND bom.EndDate IS NULL
)
SELECT AssemblyID,
ComponentID,
Name,
PerAssemblyQty,
EndDate,
ComponentLevel
FROM Parts AS p
INNER JOIN Production.Product AS pr
ON p.ComponentID = pr.ProductID
ORDER BY ComponentLevel, AssemblyID, ComponentID;
F. Använda en rekursiv CTE i en UPDATE-instruktion
I följande exempel uppdateras PerAssemblyQty
värdet för alla delar som används för att skapa produkten 'Road-550-W Yellow, 44' (ProductAssemblyID 800)
. Det gemensamma tabelluttrycket returnerar en hierarkisk lista över delar som används för att skapa ProductAssemblyID 800
och de komponenter som används för att skapa dessa delar och så vidare. Endast de rader som returneras av det gemensamma tabelluttrycket ändras.
USE AdventureWorks2022;
GO
WITH Parts (AssemblyID, ComponentID, PerAssemblyQty, EndDate, ComponentLevel) AS
(
SELECT b.ProductAssemblyID,
b.ComponentID,
b.PerAssemblyQty,
b.EndDate,
0 AS ComponentLevel
FROM Production.BillOfMaterials AS b
WHERE b.ProductAssemblyID = 800
AND b.EndDate IS NULL
UNION ALL
SELECT bom.ProductAssemblyID,
bom.ComponentID,
p.PerAssemblyQty,
bom.EndDate,
ComponentLevel + 1
FROM Production.BillOfMaterials AS bom
INNER JOIN Parts AS p
ON bom.ProductAssemblyID = p.ComponentID
AND bom.EndDate IS NULL
)
UPDATE Production.BillOfMaterials
SET PerAssemblyQty = c.PerAssemblyQty * 2
FROM Production.BillOfMaterials AS c
INNER JOIN Parts AS d
ON c.ProductAssemblyID = d.AssemblyID
WHERE d.ComponentLevel = 0;
H. Använda flera fästpunkter och rekursiva medlemmar
I följande exempel används flera fästpunkter och rekursiva medlemmar för att returnera alla överordnade till en angiven person. En tabell skapas och värden infogas för att upprätta familjegenologin som returneras av den rekursiva CTE:en.
-- Genealogy table
IF OBJECT_ID('dbo.Person', 'U') IS NOT NULL
DROP TABLE dbo.Person;
GO
CREATE TABLE dbo.Person
(
ID INT,
Name VARCHAR (30),
Mother INT,
Father INT
);
GO
INSERT dbo.Person VALUES
(1, 'Sue', NULL, NULL),
(2, 'Ed', NULL, NULL),
(3, 'Emma', 1, 2),
(4, 'Jack', 1, 2),
(5, 'Jane', NULL, NULL),
(6, 'Bonnie', 5, 4),
(7, 'Bill', 5, 4);
GO
-- Create the recursive CTE to find all of Bonnie's ancestors.
WITH Generation (ID) AS
(
-- First anchor member returns Bonnie's mother.
SELECT Mother
FROM dbo.Person
WHERE Name = 'Bonnie'
UNION
-- Second anchor member returns Bonnie's father.
SELECT Father
FROM dbo.Person
WHERE Name = 'Bonnie'
UNION ALL
-- First recursive member returns male ancestors of the previous generation.
SELECT Person.Father
FROM Generation, Person
WHERE Generation.ID = Person.ID
UNION ALL
-- Second recursive member returns female ancestors of the previous generation.
SELECT Person.Mother
FROM Generation, dbo.Person
WHERE Generation.ID = Person.ID
)
SELECT Person.ID, Person.Name, Person.Mother, Person.Father
FROM Generation, dbo.Person
WHERE Generation.ID = Person.ID;
GO
Jag. Använda analysfunktioner i en rekursiv CTE
I följande exempel visas en fallgrop som kan inträffa när du använder en analys- eller aggregeringsfunktion i den rekursiva delen av en CTE.
DECLARE @t1 TABLE (itmID INT, itmIDComp INT);
INSERT @t1 VALUES (1, 10), (2, 10);
DECLARE @t2 TABLE (itmID INT, itmIDComp INT);
INSERT @t2 VALUES (3, 10), (4, 10);
WITH vw AS
(
SELECT itmIDComp, itmID FROM @t1
UNION ALL SELECT itmIDComp, itmID FROM @t2
),
r AS
(
SELECT t.itmID AS itmIDComp,
NULL AS itmID,
CAST (0 AS BIGINT) AS N,
1 AS Lvl
FROM (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) AS t(itmID)
UNION ALL
SELECT t.itmIDComp,
t.itmID,
ROW_NUMBER() OVER (PARTITION BY t.itmIDComp ORDER BY t.itmIDComp, t.itmID) AS N,
Lvl + 1
FROM r
INNER JOIN vw AS t
ON t.itmID = r.itmIDComp
)
SELECT Lvl, N FROM r;
Följande resultat är de förväntade resultaten för frågan.
Lvl N
1 0
1 0
1 0
1 0
2 4
2 3
2 2
2 1
Följande resultat är de faktiska resultaten för frågan.
Lvl N
1 0
1 0
1 0
1 0
2 1
2 1
2 1
2 1
N
returnerar 1 för varje passering av den rekursiva delen av CTE eftersom endast delmängden av data för den rekursionsnivån skickas till ROWNUMBER
. För var och en av iterationerna i den rekursiva delen av frågan skickas endast en rad till ROWNUMBER
.
Exempel: Azure Synapse Analytics and Analytics Platform System (PDW)
J. Använda ett vanligt tabelluttryck i en CTAS-instruktion
I följande exempel skapas en ny tabell som innehåller det totala antalet försäljningsorder per år för varje säljare på Adventure Works Cycles.
USE AdventureWorks2022;
GO
CREATE TABLE SalesOrdersPerYear
WITH (DISTRIBUTION = HASH(SalesPersonID)) AS
-- Define the CTE expression name and column list.
WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear) AS
-- Define the CTE query.
(
SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
)
-- Define the outer query referencing the CTE name.
SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear
FROM Sales_CTE
GROUP BY SalesYear, SalesPersonID
ORDER BY SalesPersonID, SalesYear;
GO
K. Använda ett vanligt tabelluttryck i en CETAS-instruktion
I följande exempel skapas en ny extern tabell som innehåller det totala antalet försäljningsorder per år för varje säljare på Adventure Works Cycles.
USE AdventureWorks2022;
GO
CREATE EXTERNAL TABLE SalesOrdersPerYear
WITH
(
LOCATION = 'hdfs://xxx.xxx.xxx.xxx:5000/files/Customer',
FORMAT_OPTIONS ( FIELD_TERMINATOR = '|' )
) AS
-- Define the CTE expression name and column list.
WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear) AS
-- Define the CTE query.
(
SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
)
-- Define the outer query referencing the CTE name.
SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear
FROM Sales_CTE
GROUP BY SalesYear, SalesPersonID
ORDER BY SalesPersonID, SalesYear;
GO
L. Använda flera kommaavgränsade CTE:er i en instruktion
I följande exempel visas att två CTE:er ingår i en enda instruktion. CtEs kan inte kapslas (ingen rekursion).
WITH CountDate (TotalCount, TableName) AS
(
SELECT COUNT(datekey), 'DimDate' FROM DimDate
),
CountCustomer (TotalAvg, TableName) AS
(
SELECT COUNT(CustomerKey), 'DimCustomer' FROM DimCustomer
)
SELECT TableName, TotalCount
FROM CountDate
UNION ALL
SELECT TableName, TotalAvg FROM CountCustomer;