(一)概念
1、MySQL的CTE是在MySQL8.0版本开始支持的,公用表表达式是一个命名的临时结果集,仅在单个SQL语句(例如select、insert、delete和update)的执行范围内存在。CTE分为递归CTE和非递归CTE。
(二)意义
1、MySQL8.0之前,进行复杂查询时需要使用子查询来实现,SQL语句不仅语句复杂性能低,而且不够清晰。CTE的出现简化了复杂查询语句的编写,提高了SQL性能。
2、与子查询或者派生查询相比,CTE可以重用上次的查询结果即查询一次即可,同时,CTE可以相互引用。例如:
WITH d1 AS (SELECT ... FROM ...), d2 AS (SELECT ... FROM d1 ... )
SELECT FROM d1, d2 ...
(三)语法如下:
with cte_name1 [(column_list)] as (
查询语句
),
cte_name2 as(
查询语句
)
select * from cte_name;
注意:
查询中的列数必须与column_list
中的列数相同。 如果省略column_list
,将使用cte中查询语句中使用的列。
注意:多个cte查询语句之间用逗号分隔。
(四)cte实例:
WITH customers_in_usa AS (
SELECT
customerName, state
FROM
customers
WHERE
country = 'USA'
) SELECT
customerName
FROM
customers_in_usa
WHERE
state = 'CA'
ORDER BY customerName;
(五)递归CTE
1、递归CTE概念:递归的方式是CTE的子查询可以引用其本身,使用递归方式时,WITH子句中要使用WITH RECURSIVE代替。递归CTE子句中必须包含两个部分,一个是种子查询(不可引用自身),另一个是递归查询,这两个子查询可以通过 UNION、UNION ALL或UNION DISTINCT 连接在一起。
注意:种子SELECT只会执行一次,并得到初始的数据子集,而递归SELECT是会重复执行直到没有新的行产生为止,最终将所有的结果集都查询出来,这对于深层查询(如具有父子关系的查询)是非常有用的。
2、递归实例:查询公司的组织架构数据,查询管理层级。
(1)创建表:
CREATE TABLE emp(
id INT PRIMARY KEY NOT NULL,
name VARCHAR(100) NOT NULL,
manager_id INT NULL,
INDEX (manager_id),
FOREIGN KEY (manager_id) REFERENCES employees_mgr
(id)
);
(2)插入数据:
INSERT INTO emp VALUES
(333, "总经理", NULL),
(198, "副总1", 333),
(692, "副总2", 333),
(29, "主任1", 198),
(4610, "职员1", 29),
(72, "职员2", 29),
(123, "主任2", 692);
(3)递归查询:
WITH RECURSIVE test(id, name, path)
AS
(
SELECT id, name, CAST(id AS CHAR(200))
FROM emp WHERE manager_id IS NULL
UNION ALL
SELECT e.id, e.name, CONCAT(ep.path, ',', e.id)
FROM test AS ep JOIN emp AS e ON ep.id = e.manager_id
)SELECT * FROM test ORDER BY path;
(4)结果如下:
+------+---------+-----------------+
| id | name | path |
+------+---------+-----------------+
| 333 | 总经理| 333 |
| 198 | 副总1| 333,198 |
| 29 | 主任1| 333,198,29 |
| 4610 | 职员1| 333,198,29,4610 |
| 72 | 职员2| 333,198,29,72 |
| 692 | 副总2| 333,692 |
| 123 | 主任2| 333,692,123 |
+------+---------+-----------------+
(一)子查询概念
1、子查询是嵌套在另一个查询(如select、insert、update和delete)中的查询。子查询又称为内部查询,而包含子查询的查询称为外部查询。 子查询可以在使用表达式的任何地方使用,并且必须在括号中关闭。
2、如图所示:
(一)派生表概念
1、派生表是从select语句返回的虚拟表。派生表类似于临时表,但是在SELECT
语句中使用派生表比临时表简单得多,因为派生表没有创建临时表的步骤。派生表会在使用过后即时清除的,所以我们在简化复杂查询的时候可以考虑使用。
注意:派生表和子查询通常可以互换使用,但是与子查询不同的是,派生表必须具有别名。
(二)派生表语法
SELECT column_list FROM
( SELECT column_list FROM table_1) derived_table_name --派生表
WHERE derived_table_name.c1 > 0;
注意:派生表之间不可以相互引用。例如:
SELECT ... FROM (SELECT ... FROM ...) AS d1, (SELECT ... FROM d1 ...) AS d2,第一个查询标记为d1,在第二个查询语句中使用d1是不允许的。
(一)临时表概念
1、临时表是一种特殊类型的表,它允许您存储一个临时结果集,可以在单个会话中多次重用。
(二)创建临时表语法
1、使用CREATE TEMPORARY TABLE
语句创建临时表。请注意,在CREATE
和TABLE
关键字之间添加TEMPORARY
关键字。
2、当会话结束或连接终止时,MySQL会自动删除临时表。当您不再使用临时表时,也可以使用DROP TABLE语句来显式删除临时表。
3、一个临时表只能由创建它的客户机访问。不同的客户端可以创建具有相同名称的临时表,而不会导致错误,因为只有创建临时表的客户端才能看到它。 但是,在同一个会话中,两个临时表不能共享相同的名称。
4、临时表可以与数据库中的普通表具有相同的名称。 不推荐使用相同名称。例如,如果在示例数据库(yiibaidb)中创建一个名为employees
的临时表,则现有的employees
表将变得无法访问。 对employees
表发出的每个查询现在都是指employees
临时表。 当删除您
临时表时,永久employees
表可以再次访问。
(三)临时表实例
1、创建一个临时表:
CREATE TEMPORARY TABLE table_name (
name VARCHAR(10) NOT NULL,
value INTEGER NOT NULL
);
2、删除临时表:
drop temporary table table_name;