在撰寫 T-SQL 查詢時,巢狀子查詢層級過深往往會導致程式碼難以閱讀、維護成本高昂。以往開發者常使用暫存表或資料表變數來拆解邏輯,但這樣做會引入額外的 I/O 開銷,影響效能。SQL Server 2005 引入的 公用資料表運算式 完美解決了這個兩難困境:它兼具結構清晰與執行效能優異的雙重優勢。
假設我們要查詢國家代碼以「C」開頭的所有省份資料,傳統寫法如下:
SELECT *
FROM person.StateProvince
WHERE CountryRegionCode IN (
SELECT CountryRegionCode
FROM person.CountryRegion
WHERE Name LIKE 'C%'
);
若業務邏輯更複雜,巢狀層級疊加會讓 SQL 變得極難維護。早期解法常用資料表變數:
DECLARE @t TABLE (CountryRegionCode NVARCHAR(3));
INSERT INTO @t (CountryRegionCode)
SELECT CountryRegionCode FROM person.CountryRegion WHERE Name LIKE 'C%';
SELECT * FROM person.StateProvince WHERE CountryRegionCode IN (SELECT * FROM @t);
雖然邏輯分離了,但資料表變數底層使用 TempDB,會產生額外 I/O,不適合大數據量、高頻查詢場景。
CTE 的基本語法結構:
WITH <common_table_expression> [ ,...n ]
<common_table_expression> ::=
expression_name [ ( column_name [ ,...n ] ) ]
AS ( CTE_query_definition )
同樣的需求改寫為 CTE:
WITH cr AS (
SELECT CountryRegionCode
FROM person.CountryRegion
WHERE Name LIKE 'C%'
)
SELECT *
FROM person.StateProvince
WHERE CountryRegionCode IN (SELECT * FROM cr);
cr 即為一個公用資料表運算式,使用方式類似資料表變數,但 SQL Server 內部優化機制不同,效能顯著優於資料表變數。
WITH 子句中定義多個 CTE,以逗號分隔,彼此可互相引用(僅限向後引用)。WITH 子句中較早定義的 CTE,支援遞迴查詢(詳細用法將於後續文章介紹)。COMPUTE/COMPUTE BY、ORDER BY(除非搭配 TOP)、INTO、帶查詢提示的 OPTION、FOR XML、FOR BROWSE。DECLARE @s NVARCHAR(3); SET @s = 'C%';
; -- 必須加分號
WITH t_tree AS (
SELECT CountryRegionCode FROM person.CountryRegion WHERE Name LIKE @s
)
SELECT * FROM person.StateProvince WHERE CountryRegionCode IN (SELECT * FROM t_tree);
CTE 不僅能大幅提升複雜查詢的可讀性與維護性,其執行計畫優化也優於傳統資料表變數。掌握上述注意事項,即可在專案中放心大量採用 CTE,打造更優雅、高效的 T-SQL 程式碼。下一篇將深入探討 CTE 的遞迴應用場景。