WITH(公共表表達式)html
公共表表達式(common table expression,CTE)是一個命名的臨時結果集,存在於單個語句的範圍內,定義後能夠在該語句中引用它,可能屢次引用。下面的討論描述如何編寫使用 CTE 的語句。mysql
通用表表達式sql
若要指定公共表表達式,請使用用逗號分隔子語句的 WITH 子句。每一個子句提供一個子查詢,該子查詢生成一個結果集,每一個子查詢關聯一個名稱。如下示例在 WITH 子句中定義名爲 cte1 和 cte2 的 CTE,並在 WITH 子句後面的頂級 SELECT 中引用它們:express
1. WITH 2. cte1 AS (SELECT a, b FROM table1), 3. cte2 AS (SELECT c, d FROM table2) 4. SELECT b, d FROM cte1 JOIN cte2 5. WHERE cte1.a = cte2.c;
在包含 WITH 子句的語句中,能夠引用每一個 CTE 名稱來訪問相應的 CTE 結果集。ide
一個 CTE 名稱能夠在其餘 CTE 中引用,從而能夠基於其餘 CTE 定義 CTE。code
CTE 能夠引用自身來定義遞歸 CTE。遞歸 CTE 的常見應用包括序列生成和層次或樹結構數據的遍歷。htm
公共表表達式是 DML 語句語法的可選部分。它們是使用 WITH 子句定義的:對象
1. with_clause: 2. WITH [RECURSIVE] 3. cte_name [(col_name [, col_name] ...)] AS (subquery) 4. [, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...
cte_name 命名一個公共表表達式,能夠在包含 WITH 子句的語句中用做表引用。遞歸
AS (subquery) 的 subquery 部分稱爲「CTE 子查詢」,它生成 CTE 結果集。AS 後面的括號是必需的。get
若是公共表表達式的子查詢引用它本身的名稱,則該表達式是遞歸的。若是 WITH 子句中的任何 CTE 是遞歸的,則必須包含 RECURSIVE 關鍵字。
明確給定 CTE 的列名以下:
● 若是圓括號括起來的列表名稱跟在 CTE 名稱後面,則這些名稱就是列名稱:
1. WITH cte (col1, col2) AS 2. ( 3. SELECT 1, 2 4. UNION ALL 5. SELECT 3, 4 6. ) 7. SELECT col1, col2 FROM cte;
列表中的名稱數量必須與結果集中的列數相同。
● 不然,列名來自 AS (subquery) 部分的第一個 SELECT 的選擇列表:
1. WITH cte AS 2. ( 3. SELECT 1 AS col1, 2 AS col2 4. UNION ALL 5. SELECT 3, 4 6. ) 7. SELECT col1, col2 FROM cte;
在如下上下文中容許使用 WITH 子句:
● 在 SELECT、UPDATE 和 DELETE 語句的開頭。
1. WITH ... SELECT ... 2. WITH ... UPDATE ... 3. WITH ... DELETE ...
● 在子查詢(包括派生表子查詢)開始部分:
1.SELECT ... WHERE id IN (WITH ... SELECT ...) ... 2.SELECT * FROM (WITH ... SELECT ...) AS dt ...
● 緊跟在包含 SELECT 語句的 SELECT 語句以前:
1. INSERT ... WITH ... SELECT ... 2. REPLACE ... WITH ... SELECT ... 3. CREATE TABLE ... WITH ... SELECT ... 4. CREATE VIEW ... WITH ... SELECT ... 5. DECLARE CURSOR ... WITH ... SELECT ... 6. EXPLAIN ... WITH ... SELECT ...
同一級別只容許有一個 WITH 子句。同一級別的 WITH 後面跟 WITH 是不容許的,所以如下語句是非法的:
1. WITH cte1 AS (...) WITH cte2 AS (...) SELECT ...
要使語句合法,請使用一個 WITH 子句,用逗號分隔它的子句:
1.WITH cte1 AS (...), cte2 AS (...) SELECT ...
但若是出如今不一樣的層級,一個語句能夠包含多個WITH子句:
1.WITH cte1 AS (SELECT 1) 2.SELECT * FROM (WITH cte2 AS (SELECT 2) SELECT * FROM cte2 JOIN cte1) AS dt;
WITH 子句能夠定義一個或多個公共表表達式,但每一個 CTE 名稱對於該子句必須是惟一的。如下語句是非法的:
1.WITH cte1 AS (...), cte1 AS (...) SELECT ...
要使語句合法,請使用惟一名稱定義 CTE:
1.WITH cte1 AS (...), cte2 AS (...) SELECT ...
CTE 能夠指自身或其餘 CTE:
● 自引用 CTE 是遞歸的。
● CTE 能夠引用在同一 WITH 子句中前面定義的 CTE,但不能引用後面定義的 CTE。
這個約束排除了相互遞歸的 CTE,其中 cte1 引用 cte2,cte2 引用 cte1。其中一個引用必須是後面定義的 CTE,這是不容許的。
● 給定查詢塊中的 CTE 能夠引用在更外部層級的查詢塊中定義的 CTE,但不能引用在更內部層級的查詢塊中定義的 CTE。
爲了解析對同名對象的引用,派生表隱藏 CTE;而 CTE 隱藏基本表、臨時表和視圖。名稱解析的方法是在同一個查詢塊中搜索對象,若是找不到具備該名稱的對象依次轉到外部查詢塊。
與派生表同樣,MySQL 8.0.14 以前 CTE 不能包含外部引用。這是 MySQL 8.0.14 中取消的 MySQL 限制,而不是 SQL 標準的限制。