WITH ... AS (...) 定義一個僅在緊隨其後的單一陳述式可見的暫時結果集。不同於暫存表/表變數,CTE:
tempdb 物理儲存 (除非查詢最佳化工具決定物質化)。WITH 定義多個 CTE,互相參考。
WITH cte_name (col1, col2) AS (
SELECT col1, col2 FROM SomeTable WHERE ...
)
SELECT * FROM cte_name;
-- 原始巢狀
SELECT * FROM Person.StateProvince
WHERE CountryRegionCode IN (
SELECT CountryRegionCode FROM Person.CountryRegion WHERE Name LIKE 'C%'
);
-- CTE 版 (可讀性大幅提升)
WITH CCountries AS (
SELECT CountryRegionCode FROM Person.CountryRegion WHERE Name LIKE 'C%'
)
SELECT * FROM Person.StateProvince
WHERE CountryRegionCode IN (SELECT CountryRegionCode FROM CCountries);
-- 表變數版 (寫入 tempdb、統計資訊差)
DECLARE @t TABLE (CountryRegionCode NVARCHAR(3));
INSERT INTO @t SELECT CountryRegionCode FROM Person.CountryRegion WHERE Name LIKE 'C%';
SELECT * FROM Person.StateProvince WHERE CountryRegionCode IN (SELECT * FROM @t);
-- CTE 版 (最佳化器可直接展開、無額外 I/O)
WITH CCountries AS (
SELECT CountryRegionCode FROM Person.CountryRegion WHERE Name LIKE 'C%'
)
SELECT * FROM Person.StateProvince WHERE CountryRegionCode IN (SELECT CountryRegionCode FROM CCountries);
WITH
C1 AS (SELECT * FROM Table1 WHERE Type = 'A'),
C2 AS (SELECT * FROM Table2 WHERE Status = 1),
C3 AS (SELECT * FROM Table3 WHERE Date > '2024-01-01')
SELECT a.*, b.*, c.*
FROM C1 a JOIN C2 b ON a.ID = b.ID JOIN C3 c ON a.ID = c.ID;
WITH OrgTree AS (
-- Anchor member
SELECT EmpID, MgrID, EmpName, 0 AS Level
FROM Employee WHERE MgrID IS NULL
UNION ALL
-- Recursive member
SELECT e.EmpID, e.MgrID, e.EmpName, ot.Level + 1
FROM Employee e
INNER JOIN OrgTree ot ON e.MgrID = ot.EmpID
)
SELECT * FROM OrgTree OPTION (MAXRECURSION 100);
MAXRECURSION 0 移除 100 層限制 (謹慎使用,防無限遞歸)。
COMPUTE、ORDER BY (除非搭配 TOP)、INTO、OPTION 查詢提示、FOR XML/BROWSE。WITH 必須前置分號:;WITH CTE AS ...。WITH 前加分號 ;WITH,防止批次合併執行時語法錯誤。