WITH 子句定义,因此也称为 WITH 子句。CTE 在单条 SQL 语句中定义临时结果集,并允许在该语句的后续部分多次引用,从而提高复杂查询的可读性和可维护性。-- 定义 CTE。WITH CustomerCTE AS (SELECT customer_id, first_name, last_name, email_addressFROM customer)-- 引用 CTE。SELECT *FROM CustomerCTE;
非递归 CTE | 递归 CTE | 是否需要 Hint /*+ MERGE() */ | 流式执行 |
支持 | 支持 | 不需要 | 支持 |
with_clause:WITH [RECURSIVE]cte_name [(col_name [, col_name] ...)] AS (subquery)[, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...
参数项 | 描述 |
WITH | CTE 定义的开始关键字。 |
RECURSIVE | 可选关键字。包含 RECURSIVE 时表示允许在 CTE 中引用自身,用于构造递归查询。 |
cte_name | CTE 的名称,可在后续查询中被引用。 |
col_name | 可选的列名列表,用于指定 CTE 结果集的列名。如果省略,则使用子查询中的列名。 |
subquery | CTE 内部的子查询,定义 CTE 的内容。 |
多个 CTE | 一个 WITH 子句中可定义多个 CTE,相互之间使用半角逗号分隔。 |
WITHcte1 AS (SELECT * FROM t1, t2),cte2 AS (SELECT i1, i2 FROM cte1 WHERE i3 > 10),cte3 AS (SELECT * FROM cte2, t3 WHERE cte2.i1 = t3.i1)SELECT * FROM cte3;
WITH CustomerCTE AS (SELECT customer_id, first_name, last_name, email_addressFROM customer)SELECT *FROM CustomerCTE;
WITH 子句中定义两个 CTE,并在最终查询中使用 JOIN 进行关联。WITHCTE1 AS (SELECT customer_id, first_name, last_name, email_addressFROM customer),CTE2 AS (SELECT ss_item_sk, ss_customer_sk, ss_sold_date_sk, ss_sales_priceFROM store_sales)SELECT CTE1.first_name, CTE1.last_name, CTE2.ss_sales_priceFROM CTE1JOIN CTE2 ON CTE1.customer_id = CTE2.ss_customer_sk;
CTE1 和 CTE2 两个 CTE,分别从 customer 表和 store_sales 表读取数据。customer_id 字段进行 JOIN。+------------+-----------+----------------+| first_name | last_name | ss_sales_price |+------------+-----------+----------------+| John | Doe | 45.99 || Jane | Smith | 32.50 || Michael | Johnson | 78.25 || Emily | Brown | 19.99 || David | Wilson | 55.00 |+------------+-----------+----------------+5 rows in set (0.12 sec)
WITHSalesSummary AS (SELECT ss_customer_sk, SUM(ss_net_paid) AS total_spentFROM store_salesGROUP BY ss_customer_sk),TopCustomers AS (SELECT ss_customer_sk, total_spentFROM SalesSummaryWHERE total_spent > 1000),CustomerDetails AS (SELECT c.customer_id, c.first_name, c.last_name, tc.total_spentFROM customer cJOIN TopCustomers tc ON c.customer_id = tc.ss_customer_sk)SELECT *FROM CustomerDetails;
SalesSummary 计算每个客户的总消费金额。TopCustomers 从 SalesSummary 中筛选出消费金额超过 1000 的客户。CustomerDetails 将 customer 表的客户信息与 TopCustomers 进行关联。CustomerDetails 中提取所有数据。+-------------+------------+-----------+-------------+| customer_id | first_name | last_name | total_spent |+-------------+------------+-----------+-------------+| 1001 | John | Doe | 1523.75 || 1002 | Jane | Smith | 2105.50 || 1003 | Michael | Johnson | 1789.99 || 1004 | Emily | Brown | 1650.25 || 1005 | David | Wilson | 1875.00 |+-------------+------------+-----------+-------------+5 rows in set (0.15 sec)
UNION ALL 或 UNION DISTINCT 连接种子部分与递归部分。WITH RECURSIVE cte(n, fact) AS (SELECT 0, 1 -- 种子部分UNION ALL -- 联合方式SELECT n + 1, (n + 1) * fact FROM cte WHERE n < 5 -- 递归部分)SELECT n, fact FROM cte;
cte_max_recursion_depth 控制,默认值为1000。cte_max_recursion_depth 时,查询返回错误:Recursive query aborted after N iterations. Try increasing @@cte_max_recursion_depth to a larger value。SET cte_max_recursion_depth = N; 调整递归深度上限。WITH RECURSIVE cte(n, fact) AS (SELECT 0, 1UNION ALLSELECT n + 1, (n + 1) * fact FROM cte WHERE n < 5)SELECT n, fact FROM cte;
(0, 1)。n + 1 和 (n + 1) * fact,直至 n 达到5。employees,其中 manager_id 表示该员工的直接上级。CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100),manager_id INT);INSERT INTO employees (id, name, manager_id) VALUES(1, 'CEO', NULL),(2, 'Manager 1', 1),(3, 'Manager 2', 1),(4, 'Employee 1', 2),(5, 'Employee 2', 2),(6, 'Employee 3', 3);
WITH RECURSIVE employee_hierarchy AS (-- 种子部分:从 CEO 开始SELECTid,name,manager_id,1 AS levelFROM employeesWHERE manager_id IS NULLUNION ALL-- 递归部分:查找每个员工的下属SELECTe.id,e.name,e.manager_id,eh.level + 1FROM employees eINNER JOIN employee_hierarchy eh ON eh.id = e.manager_id)SELECT id, name, manager_id, levelFROM employee_hierarchyORDER BY level, manager_id;
+----+------------+------------+-------+| id | name | manager_id | level |+----+------------+------------+-------+| 1 | CEO | NULL | 1 || 2 | Manager 1 | 1 | 2 || 3 | Manager 2 | 1 | 2 || 4 | Employee 1 | 2 | 3 || 5 | Employee 2 | 2 | 3 || 6 | Employee 3 | 3 | 3 |+----+------------+------------+-------+6 rows in set (0.05 sec)
ORDER BY、聚合函数、窗口函数、DISTINCT 和 LIMIT 操作。cte_max_recursion_depth 限制,默认值为1000。超过限制时查询返回错误,可通过调整该变量上调上限。文档反馈