具有Having子句的存在的替代方式

时间:2016-06-13 18:26:23

标签: sql sql-server-2008 sql-server-2005

以下查询是检索其(SGT_DISBURSEMENT_REQUEST)计数仅为1的记录。它工作得很好。但是表现明智,因为我们有10万条记录,所以没有花费太多时间。

有没有更好的方法呢?

   SELECT PA.PERSON_ID,
   PA.PERSON_ACCOUNT_ID,
   DR.DISBURSEMENT_REQUEST_ID,
   SUM
   (  
        ISNULL(CD.EE_PRE_TAX_AMT,0) + 
        ISNULL(CD.EE_ADDL_PRE_TAX_AMT,0)
   ) AS EE_PRE_TAX_CONTRIB,
   DD.PRE_TAX_AMOUNT AS DISB_DTL_PRE_TAX_AMOUNT,
   SUM
   (     ISNULL(CD.EE_POST_TAX_AMT,0) + 
         ISNULL(CD.EE_ADDL_POST_TAX_AMT,0)
   ) AS EE_POST_TAX_CONTRIB,
   DD.POST_TAX_AMOUNT AS DISB_DTL_POST_TAX_AMOUNT
   FROM SGT_DISBURSEMENT_REQUEST DR
   INNER JOIN SGT_DISBURSEMENT_DETAIL DD ON DR.DISBURSEMENT_REQUEST_ID = DD.DISBURSEMENT_REQUEST_ID 
   INNER JOIN SGT_PERSON_ACCOUNT PA ON PA.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
   INNER JOIN SGT_CONTRIB_DTL CD ON CD.PERSON_ACCOUNT_ID = PA.PERSON_ACCOUNT_ID 
   WHERE DR.REQUEST_CATEGORY_VALUE = 'REFD' AND
         DD.DETAIL_CATEGORY_VALUE = 'REFD' AND
         CD.STATUS_VALUE = 'VALD' AND
         CD.POSTED_DATE <= DR.ACCEPTED_TO_PAYROLL_DATE AND
         DR.DISBURSEMENT_STATUS_VALUE <> 'CANL' AND
      EXISTS
        (
            SELECT 1 FROM SGT_DISBURSEMENT_REQUEST SDR1 
            INNER JOIN SGT_DISBURSEMENT_DETAIL SDD1 ON SDD1.DISBURSEMENT_REQUEST_ID = SDR1.DISBURSEMENT_REQUEST_ID
            WHERE SDR1.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID and SDD1.DETAIL_CATEGORY_VALUE = DD.DETAIL_CATEGORY_VALUE
            GROUP BY SDR1.PERSON_ACCOUNT_ID 
            HAVING COUNT(*) = 1
        )
   GROUP BY 
        PA.PERSON_ID, PA.PERSON_ACCOUNT_ID, DR.DISBURSEMENT_REQUEST_ID, DD.PRE_TAX_AMOUNT, DD.POST_TAX_AMOUNT

3 个答案:

答案 0 :(得分:0)

为了提高性能,您可以在Join子句中使用Filter条件,而不是where子句。在这种情况下,每个连接都会将结果限制为更少的行数。

        SELECT PA.PERSON_ID,
           PA.PERSON_ACCOUNT_ID,
           DR.DISBURSEMENT_REQUEST_ID,
           SUM
           (  
                ISNULL(CD.EE_PRE_TAX_AMT,0) + 
                ISNULL(CD.EE_ADDL_PRE_TAX_AMT,0)
           ) AS EE_PRE_TAX_CONTRIB,
           DD.PRE_TAX_AMOUNT AS DISB_DTL_PRE_TAX_AMOUNT,
           SUM
           (     ISNULL(CD.EE_POST_TAX_AMT,0) + 
                 ISNULL(CD.EE_ADDL_POST_TAX_AMT,0)
           ) AS EE_POST_TAX_CONTRIB,
           DD.POST_TAX_AMOUNT AS DISB_DTL_POST_TAX_AMOUNT
           FROM SGT_DISBURSEMENT_REQUEST DR
           INNER JOIN SGT_DISBURSEMENT_DETAIL DD ON     DR.DISBURSEMENT_REQUEST_ID = DD.DISBURSEMENT_REQUEST_ID AND DR.REQUEST_CATEGORY_VALUE = 'REFD' AND
                 DD.DETAIL_CATEGORY_VALUE = 'REFD' AND DR.DISBURSEMENT_STATUS_VALUE <> 'CANL'
           INNER JOIN SGT_PERSON_ACCOUNT PA ON PA.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
           INNER JOIN SGT_CONTRIB_DTL CD ON CD.PERSON_ACCOUNT_ID = PA.PERSON_ACCOUNT_ID AND CD.STATUS_VALUE = 'VALD' AND
                 CD.POSTED_DATE <= DR.ACCEPTED_TO_PAYROLL_DATE
           WHERE EXISTS
                (
                    SELECT 1 FROM SGT_DISBURSEMENT_REQUEST SDR1 
                    INNER JOIN SGT_DISBURSEMENT_DETAIL SDD1 ON SDD1.DISBURSEMENT_REQUEST_ID = SDR1.DISBURSEMENT_REQUEST_ID
                    WHERE SDR1.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID and SDD1.DETAIL_CATEGORY_VALUE = DD.DETAIL_CATEGORY_VALUE
                    GROUP BY SDR1.PERSON_ACCOUNT_ID 
                    HAVING COUNT(*) = 1
                )
           GROUP BY 
                PA.PERSON_ID, PA.PERSON_ACCOUNT_ID, DR.DISBURSEMENT_REQUEST_ID, DD.PRE_TAX_AMOUNT, DD.POST_TAX_AMOUNT

答案 1 :(得分:0)

如果你使用计数,它应该给你相同的结果并且更好地表现:

select * from (
SELECT PA.PERSON_ID,
   PA.PERSON_ACCOUNT_ID,
   DR.DISBURSEMENT_REQUEST_ID,
   SUM
   (  
        ISNULL(CD.EE_PRE_TAX_AMT,0) + 
        ISNULL(CD.EE_ADDL_PRE_TAX_AMT,0)
   ) AS EE_PRE_TAX_CONTRIB,
   DD.PRE_TAX_AMOUNT AS DISB_DTL_PRE_TAX_AMOUNT,
   SUM
   (     ISNULL(CD.EE_POST_TAX_AMT,0) + 
         ISNULL(CD.EE_ADDL_POST_TAX_AMT,0)
   ) AS EE_POST_TAX_CONTRIB,
   DD.POST_TAX_AMOUNT AS DISB_DTL_POST_TAX_AMOUNT
   ,count(*) over(partition by PA.PERSON_ACCOUNT_ID ) as  ct
   FROM SGT_DISBURSEMENT_REQUEST DR
   INNER JOIN SGT_DISBURSEMENT_DETAIL DD ON DR.DISBURSEMENT_REQUEST_ID = DD.DISBURSEMENT_REQUEST_ID 
   INNER JOIN SGT_PERSON_ACCOUNT PA ON PA.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
   INNER JOIN SGT_CONTRIB_DTL CD ON CD.PERSON_ACCOUNT_ID = PA.PERSON_ACCOUNT_ID 
   WHERE DR.REQUEST_CATEGORY_VALUE = 'REFD' AND
         DD.DETAIL_CATEGORY_VALUE = 'REFD' AND
         CD.STATUS_VALUE = 'VALD' AND
         CD.POSTED_DATE <= DR.ACCEPTED_TO_PAYROLL_DATE AND
         DR.DISBURSEMENT_STATUS_VALUE <> 'CANL' 

   GROUP BY 
        PA.PERSON_ID, PA.PERSON_ACCOUNT_ID, DR.DISBURSEMENT_REQUEST_ID, DD.PRE_TAX_AMOUNT, DD.PRE_TAX_AMOUNT, DD.POST_TAX_AMOUNT
        ) as x 
where x.ct = 1

答案 2 :(得分:0)

我会将其归结为#temp

SELECT DR1.PERSON_ACCOUNT_ID, SDD1.DETAIL_CATEGORY_VALUE
  FROM SGT_DISBURSEMENT_REQUEST SDR1 
  JOIN SGT_DISBURSEMENT_DETAIL SDD1 
         ON SDD1.DISBURSEMENT_REQUEST_ID = SDR1.DISBURSEMENT_REQUEST_ID
 GROUP BY SDR1.PERSON_ACCOUNT_ID, SDD1.DETAIL_CATEGORY_VALUE 
HAVING COUNT(*) = 1

join #temp 
      on #temp.PERSON_ACCOUNT_ID = DR.PERSON_ACCOUNT_ID
     and #temp.DETAIL_CATEGORY_VALUE = DD.DETAIL_CATEGORY_VALUE