公用表表达式(CTE)是一个命名的临时结果集,它存在于单个语句的范围内,以后可以在该语句中引用,可能多次。以下讨论描述了如何编写使用CTE的语句。
常用表表达式
要指定公用表表达式,请使用 WITH具有一个或多个逗号分隔子句的子句。每个子句都提供一个子查询,该子查询产生一个结果集,并将一个名称与该子查询相关联。下面的示例定义名为的CTE cte1和cte2中 WITH子句,并且是指在它们的顶层SELECT下面的WITH子句:
WITH
cte1 AS (SELECT a, b FROM table1),
cte2 AS (SELECT c, d FROM table2)
SELECT b, d FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;
确定给定CTE的列名的过程如下:
如果带括号的名称列表位于CTE名称之后,则这些名称为列名称:
WITH cte (col1, col2) AS
(
SELECT 1, 2
UNION ALL
SELECT 3, 4
)
SELECT col1, col2 FROM cte;
否则,列名来自首的选择列表中SELECT的内 部分: AS (subquery)
WITH cte AS
(
SELECT 1 AS col1, 2 AS col2
UNION ALL
SELECT 3, 4
)
SELECT col1, col2 FROM cte;
WITH同一级别 仅允许一个子句。不允许在同一级别WITH后面跟随WITH,因此这是非法的:
WITH cte1 AS (...) WITH cte2 AS (...) SELECT ...
为了使该语句合法,请使用单个 WITH子句以逗号分隔各子句:
WITH cte1 AS (...), cte2 AS (...) SELECT ...
但是,一个语句可以包含多个 WITH子句(如果它们出现在不同的级别):
WITH cte1 AS (SELECT 1)
SELECT * FROM (WITH cte2 AS (SELECT 2) SELECT * FROM cte2 JOIN cte1) AS dt;
递归公用表表达式
递归公用表表达式是具有引用其自身名称的子查询的表达式。例如:
WITH RECURSIVE cte (n) AS
(
SELECT 1
UNION ALL
SELECT n + 1 FROM cte WHERE n < 5
)
SELECT * FROM cte;
限制公用表表达式递归
对于递归CTE,重要的是递归 SELECT部分包括终止递归的条件。作为一种防止递归CTE失控的开发技术,您可以通过限制执行时间来强制终止:
- 该cte_max_recursion_depth 系统变量强制执行递归级别的热膨胀系数为数量限制。服务器终止任何递归级别高于此变量值的CTE的执行。
- 所述max_execution_time 系统变量强制用于执行超时 SELECT在当前会话中执行的语句。
- 该MAX_EXECUTION_TIME 优化器提示强制为每个查询执行超时SELECT在它出现的语句。
SET SESSION cte_max_recursion_depth = 1000000; -- permit deeper recursion
SET max_execution_time = 1000; -- impose one second timeout
WITH RECURSIVE cte (n) AS
(
SELECT 1
UNION ALL
SELECT n + 1 FROM cte
)
SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM cte;
斐波那契数列生成
斐波那契数列以两个数字0和1(或1和1)开始,其后的每个数字是前两个数字的和。如果递归产生的每一行都SELECT可以访问该序列中的前两个数字,则递归公用表表达式可以生成斐波那契数列 。以下CTE使用0和1作为前两个数字来生成10数序列:
WITH RECURSIVE fibonacci (n, fib_n, next_fib_n) AS
(
SELECT 1, 0, 1
UNION ALL
SELECT n + 1, next_fib_n, fib_n + next_fib_n
FROM fibonacci WHERE n < 10
)
SELECT * FROM fibonacci;
CTE产生以下结果:
+------+-------+------------+
| n | fib_n | next_fib_n |
+------+-------+------------+
| 1 | 0 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 2 |
| 4 | 2 | 3 |
| 5 | 3 | 5 |
| 6 | 5 | 8 |
| 7 | 8 | 13 |
| 8 | 13 | 21 |
| 9 | 21 | 34 |
| 10 | 34 | 55 |
+------+-------+------------+