Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
platí pro:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
Analytics Platform System (PDW)
koncový bod SQL Analytics ve službě Microsoft Fabric
Warehouse v Microsoft Fabric
databáze SQL v Microsoft Fabric
Určuje dočasnou pojmenovanou sadu výsledků označovanou jako běžný výraz tabulky (CTE). To je odvozeno z jednoduchého dotazu a definované v rámci rozsahu provádění jednoho SELECT
, INSERT
, UPDATE
MERGE
, nebo DELETE
příkazu. Tuto klauzuli lze také použít v příkazu jako CREATE VIEW
součást jeho definující SELECT
příkaz. Běžný výraz tabulky může obsahovat odkazy na sebe sama. Označuje se jako rekurzivní společný výraz tabulky.
Syntaxe
[ WITH <common_table_expression> [ , ...n ] ]
<common_table_expression>::=
expression_name [ ( column_name [ , ...n ] ) ]
AS
( CTE_query_definition )
Argumenty
expression_name
Platný identifikátor pro společný výraz tabulky.
expression_name se musí lišit od názvu jakéhokoli jiného společného výrazu tabulky definovaného ve stejné WITH <common_table_expression>
klauzuli, ale expression_name může být stejný jako název základní tabulky nebo zobrazení. Jakýkoli odkaz na expression_name v dotazu používá společný výraz tabulky, nikoli základní objekt.
column_name
Určuje název sloupce ve výrazu společné tabulky. Duplicitní názvy v rámci jedné definice CTE nejsou povolené. Zadaný počet názvů sloupců se musí shodovat s počtem sloupců v sadě výsledků CTE_query_definition. Seznam názvů sloupců je volitelný pouze v případě, že jsou v definici dotazu zadány jedinečné názvy všech výsledných sloupců.
CTE_query_definition
Určuje příkaz, SELECT
jehož sada výsledků naplní společný výraz tabulky. Příkaz SELECT
pro CTE_query_definition musí splňovat stejné požadavky jako při vytváření zobrazení, s výjimkou CTE nemůže definovat další CTE. Další informace naleznete v části Poznámky a CREATE VIEW.
Pokud je definováno více CTE_query_definition , definice dotazu musí být spojené jedním z těchto operátorů sady: UNION ALL
, UNION
, , EXCEPT
nebo INTERSECT
.
Pokyny k používání
Pokyny pro nerekurzivní běžné výrazy tabulek
Poznámka:
Následující pokyny platí pro nerekurzivní běžné výrazy tabulek. Pokyny, které platí pro rekurzivní běžné výrazy tabulek, najdete v tématu Pokyny pro rekurzivní běžné výrazy tabulek.
Za CTE musí následovat jeden SELECT
, INSERT
, , UPDATE
, MERGE
nebo DELETE
příkaz, který odkazuje na některé nebo všechny sloupce CTE. CTE lze také zadat v příkazu jako CREATE VIEW
součást definující SELECT
příkaz zobrazení.
V nerekurzivním CTE je možné definovat několik definic dotazů CTE. Definice musí být sloučeny jedním z těchto operátorů množiny: UNION ALL
, UNION
, INTERSECT
, nebo EXCEPT
.
CTE může odkazovat sám na sebe a dříve definované CTE ve stejné WITH
klauzuli. Přeposílání odkazů není povolené.
Zadání více než jedné WITH
klauzule v CTE není povoleno. Pokud například CTE_query_definition obsahuje poddotaz, nemůže tento poddotaz obsahovat vnořenou WITH
klauzuli, která definuje další CTE.
Další informace o vnořených cích CTE v Microsoft Fabric najdete v tématu Vnořené společné tabulkové výrazy (CTE) v datových skladech prostředků infrastruktury (Transact-SQL).
Výsledky dotazů z běžných výrazů tabulky nejsou materializovány. Každý vnější odkaz na pojmenovanou sadu výsledků vyžaduje opětovné spuštění definovaného dotazu. U dotazů, které vyžadují více odkazů na pojmenovanou sadu výsledků, zvažte místo toho použití dočasného objektu .
Uloženou proceduru nelze spustit ve společném výrazu tabulky.
V CTE_query_definition se nedají použít následující klauzule:
-
ORDER BY
(s výjimkou případu, kdyTOP
OFFSET/FETCH
je zadána klauzule) INTO
-
OPTION
klauzule s nápovědou dotazu 1 FOR BROWSE
1 Klauzuli OPTION
nelze použít uvnitř definice CTE. Lze jej použít pouze v nejkrajnějším SELECT
prohlášení.
Pokud se CTE používá v příkazu, který je součástí dávky, musí být příkaz před ním následovat středníkem.
Dotaz odkazující na CTE se dá použít k definování kurzoru.
Tabulky na vzdálených serverech lze odkazovat v CTE.
Při provádění CTE můžou všechny rady odkazující na CTE kolidovat s dalšími radami, které se zjistí, když CTE přistupuje ke svým podkladovým tabulkám stejným způsobem jako nápovědy, které odkazují na zobrazení v dotazech. V takovém případě dotaz vrátí chybu.
Pokyny pro rekurzivní běžné výrazy tabulek
Poznámka:
Následující pokyny platí pro definování rekurzivního společného výrazu tabulky. Pokyny, které platí pro nerekurzivní CES, najdete v tématu Pokyny pro nerekurzivní běžné tabulkové výrazy.
Rekurzivní definice CTE musí obsahovat alespoň dvě definice dotazu CTE, člen ukotvení a rekurzivní člen. Lze definovat více členů ukotvení a rekurzivní členy; Všechny definice dotazu členů ukotvení však musí být vloženy před první rekurzivní definici člena. Všechny definice dotazů CTE jsou členy ukotvení, pokud na samotné CTE odkazují.
Členy ukotvení musí být sloučeny jedním z těchto operátorů množiny: UNION ALL
, UNION
, INTERSECT
, nebo EXCEPT
.
UNION ALL
je jediný operátor sady povolený mezi posledním členem ukotvení a prvním rekurzivním členem a při kombinování více rekurzivních členů.
Počet sloupců v ukotvení a rekurzivních členech musí být stejný.
Datový typ sloupce v rekurzivním členu musí být stejný jako datový typ odpovídajícího sloupce v členu ukotvení.
Klauzule FROM rekurzivního členu musí odkazovat pouze jednou na expression_name CTE.
V CTE_query_definition rekurzivního členu nejsou povoleny následující položky:
SELECT DISTINCT
GROUP BY
-
PIVOT
1 HAVING
- Skalární agregace
TOP
-
LEFT
, ,RIGHT
OUTER JOIN
(INNER JOIN
je povoleno) - Poddotazy
- Tip použitý na rekurzivní odkaz na CTE uvnitř CTE_query_definition.
1 Pokud je úroveň kompatibility databáze 110 nebo vyšší. Podívejte se na zásadní změny funkcí databázového stroje v SQL Serveru 2016.
Následující pokyny platí pro použití rekurzivního běžného výrazu tabulky:
Všechny sloupce vrácené rekurzivníM CTE mají hodnotu null bez ohledu na možnou hodnotu null sloupců vrácených zúčastněnými
SELECT
příkazy.Nesprávně složený rekurzivní CTE může způsobit nekonečnou smyčku. Pokud například definice rekurzivního dotazu člena vrátí stejné hodnoty pro nadřazené i podřízené sloupce, vytvoří se nekonečná smyčka. Chcete-li zabránit nekonečné smyčce, můžete omezit počet úrovní rekurze povolených pro určitý příkaz pomocí
MAXRECURSION
nápovědy a hodnoty mezi0
32767
a vOPTION
klauzuli ,INSERT
,UPDATE
DELETE
, neboSELECT
příkazu. To vám umožní řídit provádění příkazu, dokud nevyřešíte problém s kódem, který vytváří smyčku. Výchozí hodnota pro celý server je 100. Při zadání hodnoty 0 se nepoužije žádný limit. Pro každý příkaz lze zadat pouze jednuMAXRECURSION
hodnotu. Další informace najdete v tématu nápovědy k dotazům.Zobrazení, které obsahuje rekurzivní společný výraz tabulky, nelze použít k aktualizaci dat.
Kurzory je možné definovat u dotazů pomocí objektů CTE. CTE je select_statement argument, který definuje sadu výsledků kurzoru. U rekurzivních objektů CTE jsou povoleny pouze rychlé kurzory jen vpřed a statické (snímky). Pokud je v rekurzivním CTE zadaný jiný typ kurzoru, typ kurzoru se převede na statický.
Tabulky na vzdálených serverech lze odkazovat v CTE. Pokud je vzdálený server odkazován v rekurzivním členu CTE, vytvoří se pro každou vzdálenou tabulku fond, aby k tabulkám bylo možné opakovaně přistupovat místně. Pokud se jedná o dotaz CTE, zobrazí se v plánu dotazů indexové zařazování indexů nebo opožděných fondů a další
WITH STACK
predikát. Toto je jeden ze způsobů, jak potvrdit správnou rekurzi.Analytické a agregační funkce v rekurzivní části CTE se použijí na sadu pro aktuální rekurzní úroveň, nikoli na sadu pro CTE. Funkce jako
ROW_NUMBER
provozují pouze podmnožinu dat předávaných aktuální rekurzivní úrovní, nikoli celou sadu dat předávaných rekurzivní části CTE. Další informace najdete v příkladu I. Použití analytických funkcí v rekurzivním CTE, které následuje.
Běžné výrazy tabulek ve službě Azure Synapse Analytics a Platform Platform System (PDW)
Aktuální implementace CTE ve službě Azure Synapse Analytics a systému PDW (Platform System) má následující funkce a požadavky:
CTE lze zadat v
SELECT
příkazu.CTE lze zadat v
CREATE VIEW
příkazu.CTE lze zadat v
CREATE TABLE AS SELECT
příkazu (CTAS).CTE lze zadat v
CREATE REMOTE TABLE AS SELECT
příkazu (CRTAS).CTE lze zadat v
CREATE EXTERNAL TABLE AS SELECT
příkazu (CETAS).Na vzdálenou tabulku lze odkazovat z CTE.
Na externí tabulku lze odkazovat z CTE.
V CTE je možné definovat několik definic dotazů CTE.
Za CTE může následovat
SELECT
příkazy , ,INSERT
UPDATE
,DELETE
, neboMERGE
příkazy.Běžný výraz tabulky, který obsahuje odkazy na sebe sama (rekurzivní společný výraz tabulky), se nepodporuje.
Zadání více než jedné
WITH
klauzule v CTE není povoleno. Pokud například definice dotazu CTE obsahuje poddotaz, tento poddotaz nemůže obsahovat vnořenouWITH
klauzuli, která definuje další CTE.Klauzuli
ORDER BY
nelze použít v CTE_query_definition, s výjimkou případů, kdyTOP
je klauzule zadána.Pokud se CTE používá v příkazu, který je součástí dávky, musí být příkaz před ním následovat středníkem.
Při použití vpříkazch
sp_prepare
SELECT
Pokud se však CTE používají jako součást CETAS připravenésp_prepare
, chování může odložit z SQL Serveru a dalších příkazů APS PDW kvůli způsobu implementace vazby prosp_prepare
. PokudSELECT
tento odkaz odkazuje na CTE, používá nesprávný sloupec, který v CTE neexistuje,sp_prepare
předá se bez zjištění chyby, ale tato chyba se místo toho vyvolásp_execute
.
Příklady
A. Vytvoření společného výrazu tabulky
Následující příklad ukazuje celkový počet prodejních objednávek za rok pro každého obchodního zástupce v 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. Omezení počtu a průměrů sestav pomocí běžného výrazu tabulky
Následující příklad ukazuje průměrný počet prodejních objednávek pro všechny roky pro prodejní zástupce.
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. Použití více definic CTE v jednom dotazu
Následující příklad ukazuje, jak definovat více než jeden CTE v jednom dotazu. Čárka slouží k oddělení definic dotazů CTE. Funkce FORMAT
, která se používá k zobrazení peněžních částek ve formátu měny, byla zavedena v SQL Serveru 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;
Tady je částečná sada výsledků.
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. Použití rekurzivního běžného výrazu tabulky k zobrazení více úrovní rekurze
Následující příklad ukazuje hierarchický seznam manažerů a zaměstnanců, kteří je nahlásí. Příklad začíná vytvořením a naplněním dbo.MyEmployees
tabulky.
-- 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;
Použití rekurzivního společného výrazu tabulky k zobrazení dvou úrovní rekurze
Následující příklad ukazuje manažery a zaměstnance, kteří jim hlásí. Počet vrácených úrovní je omezen na dva.
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;
Zobrazení hierarchického seznamu pomocí rekurzivního výrazu společné tabulky
Následující příklad přidá jména nadřízených a zaměstnanců a jejich odpovídající názvy. Hierarchie manažerů a zaměstnanců je navíc zdůrazněna odsazením jednotlivých úrovní.
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;
Zrušení příkazu pomocí funkce MAXRECURSION
MAXRECURSION
lze použít k zabránění špatně vytvořené rekurzivní CTE vstup do nekonečné smyčky. Následující příklad záměrně vytvoří nekonečnou smyčku a používá nápovědu MAXRECURSION
k omezení počtu úrovní rekurze na dvě.
--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);
Po opravě MAXRECURSION
chyby kódování se už nevyžaduje. Následující příklad ukazuje opravený kód.
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. Použití běžného výrazu tabulky k selektivnímu procházení rekurzivní relace v příkazu SELECT
Následující příklad ukazuje hierarchii sestavení produktů a součástí, které jsou potřebné k sestavení jízdního kola pro 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. Použití rekurzivního CTE v příkazu UPDATE
Následující příklad aktualizuje PerAssemblyQty
hodnotu pro všechny části, které se používají k sestavení produktu 'Road-550-W Yellow, 44' (ProductAssemblyID 800)
. Výraz společné tabulky vrátí hierarchický seznam částí, které se používají k sestavení ProductAssemblyID 800
, a součásti, které se používají k vytvoření těchto částí atd. Upraví se jenom řádky vrácené běžným výrazem tabulky.
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. Použití více ukotvení a rekurzivních členů
Následující příklad používá více ukotvení a rekurzivní členy k vrácení všech předků zadané osoby. Vytvoří se tabulka a hodnoty se vloží k vytvoření rodinné identity vrácené rekurzivním CTE.
-- 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
Já. Použití analytických funkcí v rekurzivním CTE
Následující příklad ukazuje nástrahy, ke kterým může dojít při použití analytické nebo agregační funkce v rekurzivní části 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;
Následující výsledky jsou očekávané výsledky dotazu.
Lvl N
1 0
1 0
1 0
1 0
2 4
2 3
2 2
2 1
Následující výsledky jsou skutečné výsledky dotazu.
Lvl N
1 0
1 0
1 0
1 0
2 1
2 1
2 1
2 1
N
vrátí hodnotu 1 pro každý průchod rekurzivní části CTE, protože pouze podmnožina dat pro danou rekurzní úroveň je předána ROWNUMBER
. Pro každou iteraci rekurzivní části dotazu se předá ROWNUMBER
pouze jeden řádek .
Příklady: Azure Synapse Analytics a Analytický platformový systém (PDW)
J. Použití běžného výrazu tabulky v rámci příkazu CTAS
Následující příklad vytvoří novou tabulku obsahující celkový počet prodejních objednávek za rok pro každého obchodního zástupce v 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. Použití běžného výrazu tabulky v rámci příkazu CETAS
Následující příklad vytvoří novou externí tabulku obsahující celkový počet prodejních objednávek za rok pro každého obchodního zástupce v 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. Použití více čárkami oddělených CTE v příkazu
Následující příklad ukazuje zahrnutí dvou CTE do jednoho příkazu. CtEs nelze vnořit (bez rekurze).
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;