Z common_table_expression (języka Transact-SQL)
Określa tymczasowy o nazwie zestaw wyników, znane jako wspólne tabela wyrażenie (CTE).Pochodzi od prostych kwerend i zdefiniowane w wykonanie zakres jednej wybierz, INSERT, UPDATE, korespondencji seryjnej lub instrukcjaDELETE.Tę klauzula można również w instrukcja CREATE VIEW jako część jego definiowanie SELECT instrukcja.Wspólne tabela wyrażenie może zawierać odwołania do samego siebie.To jest określany jako cykliczne tabelatypowewyrażenie.
Składnia
[ WITH <common_table_expression> [ ,...n ] ]
<common_table_expression>::=
expression_name [ ( column_name [ ,...n ] ) ]
AS
( CTE_query_definition )
Argumenty
expression_name
Jest prawidłowym identyfikatorem tabelatypowewyrażenie. expression_name muszą być różna od nazwy wszelkich innych wspólnych tabelawyrażenie zdefiniowane w tym samym z <common_table_expression>klauzula, ale expression_name może być taka sama jak nazwa tabela bazowa lub widoku. Wszelkie odniesienia do expression_name w kwerendzie używa tabelatypowewyrażenie i nie obiekt podstawowy.column_name
Określa nazwę kolumna w tabelatypowewyrażenie. Zduplikowane nazwy w obrębie jednej definicji CTE nie są dozwolone.Liczba nazw kolumna określonych musi odpowiadać liczba kolumn w zestaw wyników CTE_query_definition.Lista nazw kolumna jest opcjonalny, tylko wtedy, gdy różne nazwy wszystkich kolumn wynikowe są dostarczane w definicji kwerendy.CTE_query_definition
Określa SELECT instrukcja , którego zestaw wyników wypełnienie tabelatypowewyrażenie. instrukcja SELECT dla CTE_query_definition muszą spełniać te same wymagania dla tworzenia widoku, z wyjątkiem CTE nie można zdefiniować inny CTE.Aby uzyskać więcej informacji, zobacz sekcję Spostrzeżenia i CREATE VIEW (Transact-SQL).Jeżeli więcej niż jedna CTE_query_definition jest zdefiniowany, definicji kwerendy musi być przyłączony przez jeden z tych operatorów zestaw : UNION ALL, Unia, oprócz, lub część wspólna.Aby uzyskać więcej informacji na temat używania definicje kwerend rekurencyjnych CTE zobacz następujące "Uwagi" sekcja i Typowe wyrażenia tabeli za pomocą kwerend cyklicznych.
Uwagi
Wskazówki dotyczące tworzenia i używania typowych wyrażeń tabeli
Poniższe wskazówki dotyczą typowe wyrażenia tabela nierekursywne.Wskazówki, które mają zastosowanie do typowych wyrażeń tabela cykliczne zobacz "Wytyczne dla definiowania i za pomocą cyklicznych typowe tabeli wyrażenia" znajdujący się.
CTE musi następować jedną AKTUALIZACJĘ SELECT, INSERT, scalanie, lub usunąć instrukcja , która odwołuje się do niektórych lub wszystkich CTE kolumny.CTE może być również określone w instrukcja CREATE VIEW jako część Definiowanie SELECT instrukcja widoku.
Wiele definicji kwerendy CTE można zdefiniować w nierekursywne CTE.Definicje muszą zostać połączone przez jeden z tych operatorów zestaw : UNION ALL, Unia, PRZECIĘCIE lub oprócz.
CTE można odwoływać się i uprzednio zdefiniowane w tym samym z klauzulaCTEs.Nie jest dozwolone odwoływanie się do przodu.
Określanie więcej niż jeden z klauzula w CTE nie jest dozwolone.Na przykład jeśli CTE_query_definition zawiera podzapytanietego podzapytanie nie może zawierać zagnieżdżone z klauzula , która definiuje innym CTE.
Nie można używać następujących klauzul w CTE_query_definition:
KOMPUTEROWE lub COMPUTE BY
ORDER BY (z wyjątkiem przypadków, gdy określono TOP klauzula )
DO
Opcja klauzula z podpowiedzi kwerendy
XML
DLA PRZEGLĄDANIA
Gdy CTE jest używana w instrukcja , która stanowi część partia, instrukcja przed musi następować średnikami.
Kwerendy, odwoływanie się do CTE może służyć do definiowania kursor.
Tabele na serwerach zdalnych można odwoływać się w CTE.
Podczas wykonywania CTE, wskazówki, które odwołują się do CTE może powodować konflikt z innymi wskazówki, które zostały wykryte, gdy CTE uzyskuje dostęp do jego tabel podstawowych w taki sam sposób jak wskazówki, które odwołują się do widoków w kwerendach.W takim przypadku kwerenda zwraca błąd.Aby uzyskać więcej informacji, zobacz Rozdzielczość widoku.
Gdy CTE jest miejsce docelowe AKTUALIZUJĄCĄ instrukcja, muszą być zgodne wszystkie odwołania do CTE w instrukcja .Na przykład jeżeli CTE przydzielono alias w klauzulaFROM, alias musi używane wszystkich odwołań do CTE.Niejednoznacznych odwołań CTE mogą dawać łączyć nieoczekiwane zachowanie i niezamierzone kwerendy wyniki.Aby uzyskać więcej informacji, zobacz UPDATE (Transact-SQL).
Wytyczne dotyczące definiowania i używania wyrażeń tabeli wspólnego cykliczne
Do definiowania tabelawspólnej cyklicznewyrażeniestosuje się następujące wytyczne:
Definicja cykliczna CTE musi zawierać co najmniej dwie definicje kwerend CTE, zakotwiczony element członkowski i cykliczne element członkowski.Można zdefiniować wiele zakotwiczenia członków i członków cykliczne; jednak wszystkich definicji kwerendy zakotwiczony element członkowski należy umieścić przed pierwszym definicji element członkowski cykliczne.Wszystkie definicje kwerend CTEsą członkami zakotwiczenia, chyba że odwołują się one do CTE, sam.
Członkowie kontrolne muszą zostać połączone przez jeden z tych operatorów zestaw : UNION ALL, Unia, PRZECIĘCIE lub oprócz.UNION ALL jest tylko zestaw operator dozwolone między ostatnim zakotwiczony element członkowski i cykliczne pierwszego element członkowskioraz, w przypadku łączenia wielu członków cykliczne.
Liczba kolumn w kontrolnych i cykliczne członków musi być taka sama.
Typ danych kolumna w cyklicznej element członkowski musi być taki sam, jak typ danych odpowiedniej kolumna w zakotwiczony element członkowski.
FROM klauzula cykliczne element członkowski musi odwoływać się tylko jeden czas do CTE expression_name.
Następujące elementy nie są dozwolone w CTE_query_definition cykliczne element członkowski:
SELECT DISTINCT
GRUPUJ WEDŁUG
POSIADAJĄCE
Skalarną agregacja
U GÓRY
LEWY, prawy, OUTER JOIN (INNER JOIN jest dozwolone)
Podkwerendy
Wskazówka stosowane odwołanie cykliczne do CTE wewnątrz CTE_query_definition.
Poniższe wytyczne dotyczą użyciu cykliczne tabelatypowewyrażenie:
Wszystkie kolumny zwracane przez cykliczne CTE są nullable niezależnie od opcje dopuszczania wartości null kolumn zwracanych przez uczestniczące instrukcji SELECT.
Cykliczne niepoprawnie składa CTE może spowodować nieskończoną pętlę.Na przykład jeśli definicja kwerendy rekurencyjne element członkowski zwraca te same wartości dla kolumn nadrzędnych i podrzędność , jest tworzony nieskończoną pętlę.Aby zapobiec nieskończoną pętlę, można ograniczyć liczbę poziomów rekursji dla poszczególnych instrukcja przy użyciu wskazówka MAXRECURSION i wartość z przedziału od 0 do 32 767 znaków w opcji klauzula INSERT, UPDATE, korespondencji seryjnej, DELETE lub instrukcjaSELECT.Dzięki temu można kontrolować wykonywanie instrukcja , dopóki rozwiązać problem związany z kodem, który tworzy pętlę.Domyślnie serwer WWW jest 100.Określono wartość 0, brak limitu jest stosowana.Dla instrukcjamożna określić tylko jedną wartość MAXRECURSION.Aby uzyskać więcej informacji, zobacz Wskazówki kwerendy (Transact-SQL).
Widok, który zawiera tabelawspólnej cyklicznewyrażenie nie można zaktualizować danych.
Kursory może być określona na kwerendy przy użyciu CTEs.CTE jest select_statement argument, który definiuje, zestaw wyników kursor.Tylko szybkie tylko do przodu i statyczne kursory (migawka) są dozwolone dla cyklicznych CTEs.Jeśli inny typ kursor jest określona w cyklicznej CTE, typ kursor zostanie przekonwertowana na statyczne.
Tabele na serwerach zdalnych mogą odwoływać się w CTE.Jeśli serwer zdalny jest wywoływany w cyklicznej element członkowski CTE, buforu jest tworzone dla każdej tabela zdalna tabele są często dostępne lokalnie.Jeśli jest to kwerenda CTE, buforuje buforu i opóźnieniem indeksu jest wyświetlany w plan kwerend i będzie miała dodatkową predykat ze STOSU.Jest jednym ze sposobów potwierdzenia prawidłowego rekursji.
Funkcje analityczne i wartość zagregowana w części cykliczne CTE są stosowane, zestaw dla bieżącego poziom rekursji, a nie zestaw dla CTE.Funkcji, takich jak Numer_wiersza operują tylko podzbiór danych przekazanych do nich bieżący poziom rekursji, a nie cały zestaw danych pased część cykliczne CTE.Aby uzyskać więcej informacji, zobacz K. Using analytical functions in a recursive CTE.
Przykłady
A.Tworzenie tabelawspólnej prostewyrażenie
W poniższym przykładzie pokazano całkowita liczba zamówień sprzedaży rocznie dla każdego sprzedawcy w Adventure Works Cycles.
USE AdventureWorks2008R2;
GO
-- 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
B.Przy użyciu typowych tabela wyrażenie ograniczenia liczby i średnie raportu
Poniższy przykład pokazuje średnia liczba zamówień sprzedaży dla wszystkich lat dla przedstawicieli handlowych.
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;
GO
C.Wyświetlanie wielu poziomów rekursji przy użyciu tabelawspólnej cyklicznewyrażenie
Poniższy przykład pokazuje hierarchiczną listę menedżerów i pracowników, którzy podlegają ich.Przykład rozpoczyna się poprzez tworzenie i wypełnianie dbo.MyEmployees tabela.
-- 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 int NULL,
CONSTRAINT PK_EmployeeID PRIMARY KEY CLUSTERED (EmployeeID ASC)
);
-- 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);
USE AdventureWorks2008R2;
GO
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;
GO
D.Aby wyświetlić dwa poziomy rekursji przy użyciu tabelawspólnej cyklicznewyrażenie
Poniższy przykład pokazuje menedżerów i pracowników podlegających im.Liczba poziomów zwracane jest ograniczona do dwóch.
USE AdventureWorks2008R2;
GO
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 ;
GO
E.Aby wyświetlić hierarchiczną listę przy użyciu tabelawspólnej cyklicznewyrażenie
Poniższy przykład tworzy na przykład c przez dodanie nazwy menedżera i pracowników oraz ich odpowiednich tytułów.Ponadto wyróżniono hierarchii menedżerów i pracowników przez każdy poziomwcięcia.
USE AdventureWorks2008R2;
GO
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
JOIN DirectReports AS d ON e.ManagerID = d.EmployeeID
)
SELECT EmployeeID, Name, Title, EmployeeLevel
FROM DirectReports
ORDER BY Sort;
GO
F.Aby anulować instrukcjaprzy użyciu MAXRECURSION
MAXRECURSIONmożna uniemożliwić wprowadzanie w nieskończonej pętli cyklicznej błędnie sformułowany CTE.W poniższym przykładzie celowo tworzy nieskończonej pętli i korzysta z MAXRECURSION wskazówkę, aby ograniczyć liczbę poziomów rekursji do dwóch.
USE AdventureWorks2008R2;
GO
--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
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);
GO
Po poprawieniu błędów kodowania MAXRECURSION nie jest już wymagane.W poniższym przykładzie pokazano kod poprawiony.
USE AdventureWorks2008R2;
GO
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
JOIN cte ON e.ManagerID = cte.EmployeeID
)
SELECT EmployeeID, ManagerID, Title
FROM cte;
GO
G.Przy użyciu typowych tabelawyrażenie do selektywnego krokowego relacji cyklicznych w instrukcjaSELECT
Poniższy przykład pokazuje hierarchię produktu zespoły i elementy, które są wymagane do budowania rowerów dla ProductAssemblyID = 800.
USE AdventureWorks2008R2;
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;
GO
H.Za pomocą cyklicznych CTE w aktualizacji instrukcja
Następujące aktualizacje przykład PerAssemblyQty wartość dla wszystkich części, które są używane do budowania produktu "drogi-550-W żółty, 44" (ProductAssemblyID800).Wspólne tabela wyrażenie zwraca hierarchiczną listę elementów, które są używane do tworzenia ProductAssemblyID 800 i składników, które są używane do tworzenia tych części i tak dalej.Tylko wierszy zwracanych przez wspólne tabela wyrażenie są modyfikowane.
USE AdventureWorks2008R2;
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
JOIN Parts AS d ON c.ProductAssemblyID = d.AssemblyID
WHERE d.ComponentLevel = 0;
I.Za pomocą wielu członków zakotwiczenie i cykliczne
W poniższym przykładzie użyto wielu członków zakotwiczenie i cyklicznych do zwrócenia wszystkich obiektów nadrzędnych konkretnej osoby.Tworzona jest tabela , a wartości wstawione do ustanowienia rodziny genealogy zwrócone przez cykliczne 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.Za pomocą funkcji analitycznych w cyklicznej CTE
Poniższy przykład pokazuje niedogodności, który może wystąpić podczas używania analitycznej lub wartość zagregowana funkcja rekurencyjnej części 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
JOIN vw AS t ON t.itmID = r.itmIDComp
) ;
SELECT Lvl, N FROM r
Następujące wyniki są wyświetlane oczekiwane wyniki kwerendy.
Lvl N
1 0
1 0
1 0
1 0
2 4
2 3
2 2
2 1
Następujące wyniki są wyświetlane rzeczywiste wyniki kwerendy.
Lvl N
1 0
1 0
1 0
1 0
2 1
2 1
2 1
2 1
NZwraca wartość 1 dla każdego przebiegu cykliczne część CTE, ponieważ przekazywane tylko podzbiór danych dla rekursji poziom ROWNUMBER.Dla każdej iteracji części cykliczne kwerendy tylko jeden wiersz jest przekazywany do ROWNUMBER.