- SQL 教程
- SQL - 首页
- SQL - 概述
- SQL - RDBMS 概念
- SQL - 数据库
- SQL - 语法
- SQL - 数据类型
- SQL - 运算符
- SQL - 表达式
- SQL 数据库
- SQL - 创建数据库
- SQL - 删除数据库
- SQL - 选择数据库
- SQL - 重命名数据库
- SQL - 显示数据库
- SQL - 备份数据库
- SQL 表
- SQL - 创建表
- SQL - 显示表
- SQL - 重命名表
- SQL - 截断表
- SQL - 克隆表
- SQL - 临时表
- SQL - 修改表
- SQL - 删除表
- SQL - 删除表数据
- SQL - 约束
- SQL 查询
- SQL - 插入查询
- SQL - 选择查询
- SQL - Select Into
- SQL - Insert Into Select
- SQL - 更新查询
- SQL - 删除查询
- SQL - 排序结果
- SQL 视图
- SQL - 创建视图
- SQL - 更新视图
- SQL - 删除视图
- SQL - 重命名视图
- SQL 运算符和子句
- SQL - Where 子句
- SQL - Top 子句
- SQL - Distinct 子句
- SQL - Order By 子句
- SQL - Group By 子句
- SQL - Having 子句
- SQL - AND & OR
- SQL - BOOLEAN (BIT) 运算符
- SQL - LIKE 运算符
- SQL - IN 运算符
- SQL - ANY, ALL 运算符
- SQL - EXISTS 运算符
- SQL - CASE
- SQL - NOT 运算符
- SQL - 不等于
- SQL - IS NULL
- SQL - IS NOT NULL
- SQL - NOT NULL
- SQL - BETWEEN 运算符
- SQL - UNION 运算符
- SQL - UNION vs UNION ALL
- SQL - INTERSECT 运算符
- SQL - EXCEPT 运算符
- SQL - 别名
- SQL 连接
- SQL - 使用连接
- SQL - 内连接
- SQL - 左连接
- SQL - 右连接
- SQL - 交叉连接
- SQL - 全连接
- SQL - 自连接
- SQL - 删除连接
- SQL - 更新连接
- SQL - 左连接 vs 右连接
- SQL - Union vs Join
- SQL 键
- SQL - 唯一键
- SQL - 主键
- SQL - 外键
- SQL - 组合键
- SQL - 备用键
- SQL 索引
- SQL - 索引
- SQL - 创建索引
- SQL - 删除索引
- SQL - 显示索引
- SQL - 唯一索引
- SQL - 集群索引
- SQL - 非集群索引
- 高级 SQL
- SQL - 通配符
- SQL - 注释
- SQL - 注入
- SQL - 托管
- SQL - Min & Max
- SQL - 空值函数
- SQL - 检查约束
- SQL - 默认约束
- SQL - 存储过程
- SQL - NULL 值
- SQL - 事务
- SQL - 子查询
- SQL - 处理重复项
- SQL - 使用序列
- SQL - 自动递增
- SQL - 日期和时间
- SQL - 游标
- SQL - 公共表表达式
- SQL - Group By vs Order By
- SQL - IN vs EXISTS
- SQL - 数据库调优
- SQL 函数参考
- SQL - 日期函数
- SQL - 字符串函数
- SQL - 聚合函数
- SQL - 数值函数
- SQL - 文本和图像函数
- SQL - 统计函数
- SQL - 逻辑函数
- SQL - 游标函数
- SQL - JSON 函数
- SQL - 转换函数
- SQL - 数据类型函数
- SQL 有用资源
- SQL - 问答
- SQL - 快速指南
- SQL - 有用函数
- SQL - 有用资源
- SQL - 讨论
SQL - 公共表表达式 (CTE)
公共表表达式 (CTE) 可以通过使复杂查询更易于阅读和简单来简化复杂查询的管理和编写,就像数据库视图和派生表一样。我们可以通过将复杂查询分解成简单的块来重用或重写查询。
SQL 公共表表达式
MySQL 中的 WITH 子句用于指定公共表表达式。
SQL 中的公共表表达式 (CTE) 是一次性结果集,即它是一个仅在单个查询执行期间存在的临时表。它允许我们在该查询中专门处理数据,例如在 SELECT、UPDATE、INSERT、DELETE、CREATE、VIEW 或 MERGE 语句中使用它。
CTE 是临时的,因为它无法存储在任何地方以供以后使用;一旦查询执行完毕,它就会丢失。
MySQL WITH 子句
要指定公共表表达式,我们使用包含一个或多个以逗号分隔的子句的 WITH 子句。在每个子句中,我们可以提供一个产生结果集的子查询,并为该子查询分配一个名称。
在 8.0 之前的 MySQL 版本中,您无法使用 WITH 子句。
语法
以下是使用 WITH 子句创建 CTE 的语法:
WITH CTE_NAME (column_name) AS (query) SELECT * FROM CTE_NAME;
其中,
- CTE_NAME − 它是在 CTE 中分配给 CTE 的名称。
- column_name − 它是 CTE 的列名,这对于提高查询的可读性很有用。
- query − 它定义 CTE,它可以是任何有效的 SQL 查询。
- 定义 CTE 后,您可以在同一会话中的后续查询中引用它。
示例
假设我们在 MySQL 数据库中使用 CREATE TABLE 语句创建了一个名为 CUSTOMERS 的表,如下所示:
CREATE TABLE CUSTOMERS ( ID INT NOT NULL, NAME VARCHAR (20) NOT NULL, AGE INT NOT NULL, ADDRESS CHAR (25), SALARY DECIMAL (18, 2), PRIMARY KEY (ID) );
现在,我们正在向上面创建的表中插入一些记录:
INSERT INTO CUSTOMERS VALUES (1, 'Ramesh', 32, 'Ahmedabad', 2000.00 ), (2, 'Khilan', 25, 'Delhi', 1500.00 ), (3, 'Kaushik', 23, 'Kota', 2000.00 ), (4, 'Chaitali', 25, 'Mumbai', 6500.00 ), (5, 'Hardik', 27, 'Bhopal', 8500.00 ), (6, 'Komal', 22, 'Hyderabad', 4500.00 ), (7, 'Muffy', 24, 'Indore', 10000.00 );
创建的表如下所示:
ID | 姓名 | 年龄 | 地址 | 工资 |
---|---|---|---|---|
1 | Ramesh | 32 | 艾哈迈达巴德 | 2000.00 |
2 | Khilan | 25 | 德里 | 1500.00 |
3 | Kaushik | 23 | 科塔 | 2000.00 |
4 | Chaitali | 25 | 孟买 | 6500.00 |
5 | Hardik | 27 | 博帕尔 | 8500.00 |
6 | Komal | 22 | 海德拉巴 | 4500.00 |
7 | Muffy | 24 | 因多尔 | 10000.00 |
在这里,我们正在创建一个名为 CUSTOMER_AGE 的公共表表达式 (CTE),它选择所有年龄为 23 的客户。然后,我们从 CTE 中检索这些客户的 ID、姓名和年龄。
WITH CUSTOMER_AGE AS ( SELECT * FROM customers WHERE AGE = 23) SELECT ID, NAME, AGE FROM CUSTOMER_AGE;
输出
以下是上述查询的输出:
ID | 姓名 | 年龄 |
---|---|---|
3 | Kaushik | 23 |
来自多个表的 CTE
我们还可以创建一个公共表表达式 (CTE),它通过在 CTE 的子查询中使用 JOIN 操作来组合来自多个表的数据。为此,我们需要使用逗号运算符分隔每个 CTE 定义,有效地将它们合并到一个语句中。
语法
以下是多个公共表表达式 (CTE) 的基本语法:
WITH CTE_NAME1 (column_name) AS (query), CTE_NAME2 (column_name) AS (query) SELECT * FROM CTE_NAME1 UNION ALL SELECT * FROM CTE_NAME2;
我们可以将多个公共表表达式 (CTE) 与各种 SQL 操作一起使用,例如 UNION、UNION ALL、JOIN、INTERSECT 或 EXCEPT。
示例
在这里,我们定义了两个 CTE,即 'CUSTOMERS_IN_DELHI' 和 'CUSTOMERS_IN_MUMBAI',以根据他们在德里和孟买的地址来区分客户。然后,我们使用 UNION ALL 运算符将来自这两个 CTE 的结果组合到单个结果集中,检索来自这两个城市的客户信息。
WITH CUSTOMERS_IN_DELHI AS ( SELECT * FROM CUSTOMERS WHERE ADDRESS = 'Delhi'), CUSTOMERS_IN_MUMBAI AS ( SELECT * FROM CUSTOMERS WHERE ADDRESS = 'Mumbai') SELECT ID, NAME, ADDRESS FROM CUSTOMERS_IN_DELHI UNION ALL SELECT ID, NAME, ADDRESS FROM CUSTOMERS_IN_MUMBAI;
输出
上述查询的输出如下所示:
ID | 姓名 | 地址 |
---|---|---|
2 | Khilan | 德里 |
4 | Chaitali | 孟买 |
递归 CTE
公共表表达式是一个查询,它会反复循环引用自己的结果,直到返回空结果。
递归查询在其执行期间不断迭代数据的一个子集,并以自引用方式定义自身。这种自引用机制允许它反复处理和扩展其结果,直到满足停止条件。
要使 CTE 成为递归的,它必须包含 UNION ALL 语句并提供查询的第二个定义,该定义利用 CTE 本身。这允许 CTE 反复引用其自身的结果,从而在查询中创建递归行为。
示例
现在,我们使用一个名为 recursive_cust 的递归 CTE 来从上面创建的 'CUSTOMERS' 表中检索数据。最初,我们选择工资超过 3000 的客户,然后使用 UNION ALL 运算符递归地将年龄超过 25 的客户追加到结果集中:
WITH recursive_cust (ID, NAME, ADDRESS, AGE) AS ( SELECT ID, NAME, ADDRESS, AGE FROM CUSTOMERS WHERE SALARY > 3000 UNION ALL SELECT ID, NAME, ADDRESS, AGE FROM CUSTOMERS WHERE AGE > 25 ) SELECT * FROM recursive_cust;
输出
执行上述查询时,将递归显示来自客户表中年龄大于 25 或工资大于 3000 的所有数据,如下所示:
ID | 姓名 | 地址 | 年龄 |
---|---|---|---|
4 | Chaitali | 孟买 | 25 |
5 | Hardik | 博帕尔 | 27 |
6 | Komal | 海德拉巴 | 22 |
7 | Muffy | 因多尔 | 24 |
1 | Ramesh | 艾哈迈达巴德 | 32 |
5 | Hardik | 博帕尔 | 27 |
示例
在以下查询中,我们使用一个名为 Numbers 的递归 CTE 来生成并显示从 1 到 5 的数字。递归部分不断将 1 添加到前一个值,直到达到 5,从而创建一个序列:
WITH RECURSIVE Numbers AS ( SELECT 1 AS N UNION ALL SELECT N + 1 FROM Numbers WHERE N < 5 ) SELECT n FROM Numbers;
输出
执行上述查询后,我们得到以下输出:
N |
---|
1 |
2 |
3 |
4 |
5 |
CTE 的优势
以下是 CTE 的优点:
CTE 使代码维护更容易。
它提高了代码的可读性。
它提高了查询的性能。
CTE 允许简单地实现递归查询。
CTE 的劣势
以下是 CTE 的缺点:
CTE 只能被递归成员引用一次。
我们不能在存储过程中使用表变量和 CTE 作为参数。
CTE 可以代替视图使用,但 CTE 无法嵌套,而视图可以。