SQL-CTE公用表达式

Posted 面具下的戏命师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL-CTE公用表达式相关的知识,希望对你有一定的参考价值。

SQL-CTE公用表达式

CTE(Common Table Expression) 公用表表达式,它是在单个语句的执行范围内定义的临时结果集,只在查询期间有效。它可以自引用,也可在同一查询中多次引用,实现了代码段的重复利用。

CTE使用范围
  ⒈ 创建递归查询,这个应该是CTE最好用的地方
  ⒉ 在同一语句中多次引用生成的表
  3. 减少子查询和表变量,提高执行效率

CTE的作用

公用表表达式(CTE)是一个在查询中定义的临时命名结果集,将在 FROM 子句中使用它。每个 CTE 仅被定义一次(但在其作用域内可以被引用任意次),并且在该查询生存期间将一直生存,而且可以使用 CTE 来执行递归操作。因为 UNION ALL 的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用 WITH AS 短语,则只要执行一遍即可。如果 WITH AS 短语所定义的表名被调用两次以上,则优化器会自动将 WITH AS 短语所获取的数据放入一个临时表里,如果只是被调用一次则不会,很多查询通过这种方法都可以提高速度。

WITH AS的含义

WITH AS 短语,也叫做子查询部分(SUBQUERY FACTORING),它定义一个 SQL 片断,该 SQL 片断会被整个 SQL 语句所用到。它可以有效提高 SQL 语句的可读性,也可以用在 UNION ALL 的不同部分,作为提供数据的部分。

CET语法

语法格式
WITH <公用表表达式子句>{, <公用表表达式子句>}                                                            
<公用表表达式子句>::=<公用表表达式名 [ ( <列名>{,<列名>} ) ] AS ( 公用表表达式子 
查询语句)>                                                                                                                           

参数
1.<公用表表达式名> 公用表表达式的有效标识符;
2.<列名> 指明被创建的公用表表达式中列的名称;
3.<公用表表达式子查询语句> 标识公用表表达式所基于的表的行和列,其语法遵照SELECT 语句的语法规则。

WITH cte_name ( column_name [,...n] )
AS
(
    CTE_query_definition
) 
或
WITH cte_name1 ( column_name [,...n] )
AS
(
    CTE_query_definition
) ,
cte_name2 ( column_name [,...n] )
AS
(
    CTE_query_definition
) 

注意:

1.使用CTE的SQL语句应紧跟在相关的CTE后面。
2.多重CTE中间用逗号,分隔。
3.可以被紧跟着的一条SQL语句所使用多次,但不能被紧跟着的多条SQL语句使用

图例

使用说明
1.<公用表表达式名>必须与在同一 WITH 子句中定义的任何其他公用表表达式的名称不同,但公用表表达式名可以与基表或基视图的名称相同。在查询中对公用表表达式名的任何引用都会使用公用表表达式,而不使用基对象;
2.<列名>在一个 CTE 定义中不允许出现重复的列名。指定的列名数必须与<公用表表达式子查询语句>结果集中列数匹配。只有在查询定义中为所有结果列都提供了不同的名称时,列名称列表才是可选的;
3.<公用表表达式子查询语句>指定一个结果集填充公用表表达式的 SELECT 语句。除了 CTE 不能定义另一个 CTE 以外,<公用表表达式子查询语句> 的 SELECT 语句必须满足与创建视图时相同的要求;
4.公用表表达式后面必须直接跟使用 CTE 的 SQL 语句,否则无效。

使用示例

1、 查询临时结果集

WITH cte(CategoryID,CategoryName,ParentID,CategoryLevel)
AS (
  SELECT CategoryID
      ,CategoryName
      ,ParentID
      ,CategoryLevel
  FROM Category
  WHERE Status = 1 and parentid = 23
)
select * from cte;

2、递归查询

create table cte_test
    (
      id NUMBER, 
      pid NUMBER, 
      name VARCHAR(5), 
      age NUMBER
     );

insert into cte_test values(1,0,\'a\',61);
insert into cte_test values(2,1,\'b1\',45);
insert into cte_test values(3,1,\'b2\',42);
insert into cte_test values(4,2,\'c1\',35);
insert into cte_test values(5,2,\'c2\',31);
insert into cte_test values(6,3,\'c3\',29);
insert into cte_test values(7,3,\'c4\',32);
commit;

WITH
        OURCTE (ID, PID, NAME, AGE, EMPLEVEL) AS
        (
                SELECT ID, PID, NAME, AGE, 1 EMPLEVEL FROM CTE_TEST WHERE PID = 0
                
                UNION ALL
                
                SELECT
                        E.ID  ,
                        E.PID ,
                        E.NAME,
                        E.AGE ,
                        CTE.EMPLEVEL + 1
                FROM
                        CTE_TEST E
                INNER JOIN OURCTE CTE
                ON
                        E.PID = CTE.ID
                WHERE
                        E.PID <>0
        )
SELECT * FROM OURCTE ORDER BY EMPLEVEL;

3、cte结果集和数据表关联

WITH cte(CategoryID,CategoryName,ParentID,CategoryLevel)
AS (
  SELECT CategoryID
      ,CategoryName
      ,ParentID
      ,CategoryLevel
  FROM Category(NOLOCK)
  WHERE Status = 1 and parentid = 23
)
select p.ProductId,p.ProductName,c.CategoryID,c.CategoryName,c.CategoryLevel 
from product p(NOLOCK)
inner join cte c(NOLOCK) on p.CategoryId=c.CategoryI

4、公用表达式的多次引用

WITH CTE_Test
  AS
  (
      SELECT * FROM Person_1
  )
  SELECT * FROM CTE_Test AS a  --第一次引用
  INNER JOIN  CTE_Test AS b    --第二次引用
  ON a.Id = b.Id
  ORDER BY a.Id DESC

5、多条语句引用会报错,CTE只能在接下来一条语句中使用,因此,当需要接下来的一条语句中引用多个CTE时,可以定义多个,中间用逗号分隔。

WITH CTE_Test1
AS
(
SELECT * FROM Person_1
),
CTE_Test2
AS
(
SELECT * FROM Person_2
)
SELECT * FROM CTE_Test1
UNION
SELECT * FROM CTE_Test2

6、利用公用表表达式将表 TEST1 中的记录插入到 TEST2 表

INSERT INTO TEST2 WITH CTE1 AS(SELECT * FROM TEST1)
SELECT * FROM CTE1;

 

以上是关于SQL-CTE公用表达式的主要内容,如果未能解决你的问题,请参考以下文章

公用表表达式(CTE)

T-SQL 公用表表达式(CTE)

T-SQL 之 公用表表达式(CTE)

无法从多个公用表表达式(WITH)中多次查询?

Sql Server 公用表达式(CTE)

公用表表达式,为啥要分号?