SQL中复杂子查询的多个COUNT

时间:2018-02-08 12:41:49

标签: sql sql-server xml xslt count

我有一个带子查询的复杂SQL查询,它累计要在XSLT中使用的总和。 DB本质上返回XML行,XSL与它们一起工作。现在整个过程都运行得很好,但很遗憾看起来查询中有很多重复,我认为没有必要。

基本上我在子查询中有三次相同的COUNT查询,但是有不同的WHERE语句。一个查询从表中获取全部,一个获取子部分,一个获得不同的子部分。除了两个附加条件之外,查询完全相同。

我已经看过一些使用SUM的解决方案,但由于查询是一个子查询并且包含连接,因此它们确实不起作用。

我选择和加入的表格相当大。其中一个查询计算速度相当快,但是多个相同的选择会大大增加加载时间。

有没有办法组合这些子查询,以便大选择只发生一次而不是3次?

SELECT  Matrix.FT_CODE as Code

    ,   (   SELECT  COUNT(Partner.TOPIC_ID)
            FROM    EXP_EXPERTISE_TOPIC AS Partner INNER JOIN KNW_AP AS Expert ON Partner.EXPERTISE_ID = Expert.AP_ID 
            INNER JOIN AK_PERS AS Person ON Expert.AP_AK_PE_ID = Person.PE_ID       
            WHERE   Matrix.FT_CODE=Partner.TOPIC_ID and AP_DATE_EXPIRED > getdate()
            )   AS APTotal

    ,   (   SELECT  COUNT(Partner.TOPIC_ID)
            FROM    EXP_EXPERTISE_TOPIC AS Partner INNER JOIN KNW_AP AS Expert ON Partner.EXPERTISE_ID = Expert.AP_ID 
            INNER JOIN AK_PERS AS Person ON Expert.AP_AK_PE_ID = Person.PE_ID
            WHERE   (Matrix.FT_CODE BETWEEN substring(Partner.TOPIC_ID,1,5)+'00.00.00.00'  AND substring(Partner.TOPIC_ID,1,5)+'99.99.99.99' ) and AP_DATE_EXPIRED > getdate()
            )   AS APSum2

    ,   (   SELECT  COUNT(Partner.TOPIC_ID)
            FROM    EXP_EXPERTISE_TOPIC AS Partner INNER JOIN KNW_AP AS Expert ON Partner.EXPERTISE_ID = Expert.AP_ID 
            INNER JOIN AK_PERS AS Person ON Expert.AP_AK_PE_ID = Person.PE_ID
            WHERE   (Matrix.FT_CODE BETWEEN substring(Partner.TOPIC_ID,1,8)+'00.00.00'  AND substring(Partner.TOPIC_ID,1,8)+'99.99.99' ) and AP_DATE_EXPIRED > getdate()
            )   AS APSum3

FROM        BTA_FINAL AS Matrix         
WHERE       Matrix.FT_CODE BETWEEN '1.00.00.00.00.00' AND '1.99.99.99.99.99'
FOR         XML AUTO

此查询是用XML文件编写的,并使用XLS进行渲染,因此在完成数据库后我几乎无法进行数据计算。

示例结果可能如下所示:

<Matrix Code="1.09.17.06.04.00" APTotal="11" APSum2="564" APSum3="75" />

我循环了几百个以生成我的标记。这些数字是条件渲染所必需的。

2 个答案:

答案 0 :(得分:0)

在SQL Server中,您可以使用CTE(公用表表达式)而不是子查询。 https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql

您可以创建CTE然后应用where子句。这将导致更短更清晰的代码。

答案 1 :(得分:0)

当你有重复的查询时,CTE确实是正确的方法。我想出了2:

WITH PartnerCTE AS
(
SELECT  Partner.TOPIC_ID, Matrix.FT_CODE
        FROM    EXP_EXPERTISE_TOPIC AS Partner INNER JOIN KNW_AP AS Expert 
        ON Partner.EXPERTISE_ID = Expert.AP_ID 
        INNER JOIN AK_PERS AS Person ON Expert.AP_AK_PE_ID = Person.PE_ID  
    WHERE AP_DATE_EXPIRED > getdate()   
)
SELECT  Matrix.FT_CODE as Code

,   (   SELECT  COUNT(TOPIC_ID)
        FROM PartnerCTE 
        WHERE   Matrix.FT_CODE=Partner.TOPIC_ID
        )   AS APTotal

,   (   SELECT  COUNT(TOPIC_ID)
        FROM PartnerCTE 
        WHERE   (Matrix.FT_CODE BETWEEN substring(PartnerCTE.TOPIC_ID,1,5)+'00.00.00.00'  AND substring(PartnerCTE.TOPIC_ID,1,5)+'99.99.99.99' )
        )   AS APSum2

,   (   SELECT  COUNT(TOPIC_ID)
        FROM PartnerCTE 
        WHERE   (Matrix.FT_CODE BETWEEN substring(PartnerCTE.TOPIC_ID,1,8)+'00.00.00'  AND substring(PartnerCTE.TOPIC_ID,1,8)+'99.99.99' )
        )   AS APSum3

 FROM        BTA_FINAL AS Matrix         
 WHERE       Matrix.FT_CODE BETWEEN '1.00.00.00.00.00' AND '1.99.99.99.99.99'
 FOR         XML AUTO

和第二个

WITH PartnerCTE AS
  (
    SELECT  Partner.TOPIC_ID, Matrix.FT_CODE
        FROM    EXP_EXPERTISE_TOPIC AS Partner INNER JOIN KNW_AP AS Expert ON Partner.EXPERTISE_ID = Expert.AP_ID 
        INNER JOIN AK_PERS AS Person ON Expert.AP_AK_PE_ID = Person.PE_ID  
    WHERE AP_DATE_EXPIRED > getdate()   
   )

 SELECT  

    Matrix.FT_CODE as Code,
    SUM(CASE
        WHEN Matrix.FT_CODE=PartnerCTE.TOPIC_ID THEN 1
        ELSE 0
    )END APTotal,
    SUM(CASE
        WHEN Matrix.FT_CODE BETWEEN substring(PartnerCTE.TOPIC_ID,1,5)+'00.00.00.00'  AND substring(PartnerCTE.TOPIC_ID,1,5)+'99.99.99.99' THEN 1
        ELSE 0
    )END APSum2,
        SUM(CASE
        WHEN Matrix.FT_CODE BETWEEN substring(PartnerCTE.TOPIC_ID,1,8)+'00.00.00'  AND substring(PartnerCTE.TOPIC_ID,1,8)+'99.99.99' THEN 1
        ELSE 0
    )END APSum3,

        FROM  PartnerCTE,  BTA_FINAL AS Matrix
        GROUP BY Matrix.FT_CODE

另一次尝试,取消了一些重复的字符串处理:

WITH PartnerCTE AS
(
SELECT  
    Partner.TOPIC_ID,
    LEFT(Partner.TOPIC_ID,5) TOPIC_ID5,
    LEFT(Partner.TOPIC_ID,8) TOPIC_ID8,
    FROM    EXP_EXPERTISE_TOPIC AS Partner INNER JOIN KNW_AP AS Expert ON Partner.EXPERTISE_ID = Expert.AP_ID 
    INNER JOIN AK_PERS AS Person ON Expert.AP_AK_PE_ID = Person.PE_ID  
WHERE AP_DATE_EXPIRED > getdate()   
)

SELECT  

Matrix.FT_CODE as Code,
SUM(CASE
    WHEN Matrix.FT_CODE=PartnerCTE.TOPIC_ID THEN 1
    ELSE 0
)END APTotal,
SUM(CASE
    WHEN Matrix.FT_CODE BETWEEN TOPIC_ID5+'00.00.00.00'  AND TOPIC_ID5+'99.99.99.99' THEN 1
    ELSE 0
)END APSum2,
    SUM(CASE
    WHEN Matrix.FT_CODE BETWEEN TOPIC_ID8+'00.00.00'  AND TOPIC_ID8+'99.99.99' THEN 1
    ELSE 0
)END APSum3,

    FROM  PartnerCTE,  BTA_FINAL AS Matrix
    GROUP BY Matrix.FT_CODE