又叫通用表表达式,简称CTE(Common Table Expression)。CTE是一个命名的临时结果集,作用范围是当前语句。CTE可以理解成一个可以复用的子查询,当然跟子查询还是有点区别的,CTE可以引用其他CTE,但是子查询不能引用其他子查询。所以可以考虑代替子查询。
根据语法结构和执行方式不同,共用表表达式分为普通公用表表达式
和递归公用表表达式
2种。
普通公用表表达式
语法结构
WITH CTE名称
AS (子查询)
SELECT|DELETE|UPDATE 语句;
比如,查询员工所在部门的信息。
子查询:
SELECT * FROM departments
WHERE department_id IN (
SELECT DISTINCT department_id
FROM employees);
公用表表达式:
WITH emp_dept_id
AS (SELECT DISTINCT department_id FROM employees)
SELECT *
FROM departments d JOIN emp_dept_id e
ON d.department_id = e.department_id;
定义过公用表表达式之后的查询,可以像表一样使用
递归公用表表达式
可以自己调用自己。语法结构:
WITH RECURSIVE
CTE名称 AS (子查询)
SELECT|DELETE|UPDATE 语句;
递归公用表表达式由2部分组成,分别是种子查询
和递归查询
,中间通过关键字UNION[ALL]进行连接。这里的种子查询,意思是获得递归的初始值
。这个查询只会运行一次,以创建初始数据集,之后递归查询会一直执行,直到没有任何新的查询数据产生,递归返回。
比如,有张employee表,包含employee_id,last_name和manager_id三个字段。假设b是a的下属,c是b的下属,那么c是a的下下属。我们如何查出所有具有下下属身份的人员信息?
以前,我们得至少进行四次查询才能搞定:
- 第一步,先找出初代管理者,将结果存入临时表。
- 第二步,找出所有以初代管理者为管理者的人,得到一个下属集,把结果存入临时表。
- 第三步,找出所有以下属为管理者的人,得到一个下下属集,把结果存入临时表。
- 第四步,找出所有以下下属为管理的人,得到一个结果集。
如果第四步的结果为空,则计算结束,否则就必须继续进行。一直到结果集为空为止。
使用公用表表达式的话,只要一个sql就搞定了:
WITH RECURSIVE cte
AS
(
SELECT employee_id, last_name, manager_id, 1 AS n FROM employee WHERE employee_id = 100
--种子查询,找到第一代领导
UNION ALL
SELECT a.employee_id, a.last_name, a.manager_id, n+1
FROM employee AS A JOIN cte
ON (a.manager_id = cte.employee_id) --递归查询,找出以递归公用表表达式的人为领导的人
)
SELECT employee_id, last_name FROM cte WHERE n >= 3;
总之,递归公用表表达式对于查询一个有共同的根节点的树形结构数据,非常有用。它可以不受层级的限制,轻松查出所有节点的数据。如果用其他的查询方式,就比较复杂了。
小结
公用表表达式的作用是可以替代子查询,而且可以被多次引用。递归公用表表达式对查询有一个共同根节点的树形结构数据非常高效,可以轻松搞定其他查询方式难以处理的查询。