zoukankan      html  css  js  c++  java
  • 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;
  • 相关阅读:
    便 加权并查集
    bzoj 4565 状压区间dp
    bzoj 2242 [SDOI2011]计算器 快速幂+扩展欧几里得+BSGS
    poj 3243 扩展BSGS
    bzoj 3239 poj 2417 BSGS
    51nod 1135 原根 就是原根...
    bzoj 2005 能量采集 莫比乌斯反演
    约会 倍增lca
    bzoj 2186 [Sdoi2008]沙拉公主的困惑 欧拉函数
    IE下textarea去除回车换行符
  • 原文地址:https://www.cnblogs.com/jkin/p/12794222.html
Copyright © 2011-2022 走看看