SQL 公用表表达式(CTE)的用法(WITH AS短语)

  • 亚历山高
  • 2023-12-25
  • 183 人已阅读


对于SELECT查询语句来说,通常情况下,为了使T-SQL代码更加简洁和可读,在一个查询中引用另外的结果集都是通过视图而不是子查询来进行分解的.但是,视图是作为系统对象存在数据库中,那对于结果集仅仅需要在存储过程或是用户自定义函数中使用一次的时候,使用视图就显得有些奢侈了.

    公用表表达式(Common Table Expression)是SQL SERVER 2005版本之后引入的一个特性.CTE可以看作是一个临时的结果集,可以在接下来的一个SELECT,INSERT,UPDATE,DELETE,MERGE语句中被多次引用。使用公用表达式可以让语句更加清晰简练.

     除此之外,根据微软对CTE好处的描述,可以归结为四点:

  •      可以定义递归公用表表达式(CTE)

  •      当不需要将结果集作为视图被多个地方引用时,CTE可以使其更加简洁

  •     GROUP BY语句可以直接作用于子查询所得的标量列

  •     可以在一个语句中多次引用公用表表达式(CTE)

公用表表达式(CTE)的定义

公用表达式的定义非常简单,只包含三部分:

  1.   公用表表达式的名字(在WITH之后)

  2.   所涉及的列名(可选)

  3.   一个SELECT语句(紧跟AS之后)

    在MSDN中的原型:

WITH expression_name [ ( column_name [,...n] ) ] 

AS ( CTE_query_definition )


WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到。有的时候,是为了让SQL语句的可读性更高些, 也有可能是在UNION ALL的不同部分,作为提供数据的部分。
特别对于UNION ALL比较有用。因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可。如果WITH AS短语所定义的表名被调用两次以上,则优化器会自动将WITH AS短语所获取的数据放入一个TEMP表里,如果只是被调用一次,则不会。而提示materialize则是强制将WITH AS短语里的数据放入一个全局临时表里。很多查询通过这种方法都可以提高速度。

具体实例:

image.png

代码如下:


WITH CTE AS (

    SELECT 

        cSupplierName AS 供应商,

        CASE WHEN cPartType = '产成品' THEN ROUND(SUM(fFinishQuantity * ISNULL(BZDJ, 0)), 2) END AS 产成品到货额,

        CASE WHEN cPartType = '半成品' THEN ROUND(SUM(fFinishQuantity * ISNULL(BZDJ, 0)), 2) END AS 半成品到货额,

        CASE WHEN cPartType = '原材料' THEN ROUND(SUM(fFinishQuantity * ISNULL(BZDJ, 0)), 2) END AS 原材料到货额,

        ROUND(SUM(fFinishQuantity * ISNULL(BZDJ, 0)), 2) AS 总到货额

    FROM S_PurchasingApply a

    LEFT JOIN F_CostMaterialPrice b ON a.cPartCode = b.CLBM

    LEFT JOIN 

(

        SELECT b.cInvCode, ROUND(b.iSVCost, 2) AS iSVCost

        FROM (SELECT MAX(ID) AS ID, cInvCode FROM [UFDATA_002_2015].[dbo].PurSettleVouchs GROUP BY cInvCode) a

        INNER JOIN [UFDATA_002_2015].[dbo].PurSettleVouchs b ON a.ID = b.ID AND a.cInvCode = b.cInvCode

        WHERE b.iSVCost > 0

    ) c ON a.cPartCode = c.cInvCode

    WHERE CONVERT(NVARCHAR(10), dtFinishDate, 23) BETWEEN '2023-01-01' AND '2023-12-31'

        AND (cPartType LIKE '%产成品%' OR cPartType LIKE '%半成品%' OR cPartType LIKE '%原材料%')

        AND fFinishQuantity > 0 AND cSupplierName IS NOT NULL AND cSupplierName <> ''

    GROUP BY cSupplierName, cPartType

)

SELECT 

    供应商,

    SUM(产成品到货额) AS 产成品到货额,

    SUM(半成品到货额) AS 半成品到货额,

    SUM(原材料到货额) AS 原材料到货额,

    SUM(总到货额) AS 总到货额

FROM CTE

GROUP BY 供应商


UNION ALL


SELECT '合计' AS 供应商, 

    SUM(产成品到货额) AS 产成品到货额,

    SUM(半成品到货额) AS 半成品到货额,

    SUM(原材料到货额) AS 原材料到货额,

    SUM(总到货额) AS 总到货额

FROM CTE


Top