1. 程式人生 > 資料庫 >MySQL的SQL語句 - 資料操作語句(17)- WITH 語句(1)

MySQL的SQL語句 - 資料操作語句(17)- WITH 語句(1)

WITH(公共表表達式)

公共表表達式(common table expression,CTE)是一個命名的臨時結果集,存在於單個語句的範圍內,定義後可以在該語句中引用它,可能多次引用。下面的討論描述如何編寫使用 CTE 的語句。

通用表表達式

若要指定公共表表達式,請使用用逗號分隔子語句的 WITH 子句。每個子句提供一個子查詢,該子查詢生成一個結果集,每個子查詢關聯一個名稱。以下示例在 WITH 子句中定義名為 cte1 和 cte2 的 CTE,並在 WITH 子句後面的頂級 SELECT 中引用它們:

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 結果集。

一個 CTE 名稱可以在其他 CTE 中引用,從而可以基於其他 CTE 定義 CTE。

CTE 可以引用自身來定義遞迴 CTE。遞迴 CTE 的常見應用包括序列生成和層次或樹結構資料的遍歷。

公共表表達式是 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 後面的括號是必需的。

如果公共表表達式的子查詢引用它自己的名稱,則該表示式是遞迴的。如果 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 標準的限制。

官方網址: