2017-05-22 78 views
-1

我有這個sp做一個需要每天的報告。我如何執行當天的部分?像我寫的那樣好,或者那是一種簡單的方法?!存儲過程的每日報告

ALTER PROCEDURE [dbo].[pr_Report] 
    @YearOfRegistration INT 
AS 
    SELECT 
     peCountryID, 
     peCountryName as coName, 
     ISNULL(SUM(CASE WHEN peIsSubmittedFL = 1 THEN 1 ELSE 0 END),0) AS rdValue1, 
     ISNULL(SUM(CASE WHEN peIsSubmittedFL = 0 THEN 1 ELSE 0 END),0) AS rdValue2, 
     COUNT(*) AS Total 
    FROM 
     vPerson 
    WHERE 
     @YearOfRegistration = 0 
     OR peYearOfRegistration = @YearOfRegistration 
     AND (DATEPART(dd, peSubmitDate) = DATEPART(dd, GETDATE()) 
     AND DATEPART(MM, peSubmitDate) = DATEPART(MM, GETDATE()) 
     AND DATEPART(yy, peSubmitDate) = DATEPART(YY, GETDATE())) 
    GROUP BY 
     peCountryofResidencyID, peCountryOfResidencyName 

回答

1

邏輯是正確的,但這是一個非常糟糕的方法。儘可能避免對數據調用函數,特別是在where子句中,因爲這意味着不能使用底層列上的任何索引。

你的謂語將被更好地寫成:

WHERE peSubmitDate >= CAST(GETDATE() AS DATE) 
AND  peSubmitDate < DATEADD(DAY, 1, CAST(GETDATE() AS DATE)); 

這樣索引可以使用,並且您的查詢sargable

當它發生時,轉換DATETIMEDATE(反之亦然)實際上是不使用函數的規則的例外,所以您可以將其縮短爲:

WHERE CONVERT(DATE, peSubmitDate) = CONVERT(DATE, GETDATE()) 

另一點我儘管使用OR來適應您的選項(按年份篩選或返回所有記錄)看起來會更好,但您會發現擁有兩個單獨的查詢會更好。所以您的最終SP可能是:

ALTER PROC [dbo].[pr_Report] @YearOfRegistration INT 
AS 
BEGIN 
    IF (@YearOfRegistration = 0) 
    BEGIN 
     SELECT peCountryID, 
       peCountryName as coName, 
       ISNULL(SUM(CASE WHEN peIsSubmittedFL = 1 THEN 1 ELSE 0 END),0) AS rdValue1, 
       ISNULL(SUM(CASE WHEN peIsSubmittedFL = 0 THEN 1 ELSE 0 END),0) AS rdValue2, 
       COUNT(*) AS Total 
     FROM vPerson 
     WHERE CONVERT(DATE, peSubmitDate) = CONVERT(DATE, GETDATE()) 
     GROUP BY peCountryofResidencyID,peCountryOfResidencyName 
    END 
    ELSE 
    BEGIN 
     SELECT peCountryID, 
       peCountryName as coName, 
       ISNULL(SUM(CASE WHEN peIsSubmittedFL = 1 THEN 1 ELSE 0 END),0) AS rdValue1, 
       ISNULL(SUM(CASE WHEN peIsSubmittedFL = 0 THEN 1 ELSE 0 END),0) AS rdValue2, 
       COUNT(*) AS Total 
     FROM vPerson 
     WHERE CONVERT(DATE, peSubmitDate) = CONVERT(DATE, GETDATE()) 
     AND  peYearOfRegistration = @YearOfRegistration 
     GROUP BY peCountryofResidencyID,peCountryOfResidencyName; 

    END 
END 
+0

「儘可能避免調用函數,尤其是在where子句中,因爲這意味着底層列上的任何索引都不能使用」與您使用CAST(),DATEADD( )'和'WHERE'子句中的'GETDATE()'。也許你可以澄清它爲少數誰可能會困惑。 – HABO

+0

我已經說過,在datetime和date之間進行轉換和轉換是這個規則的例外,而'GETDATE()'是一個運行時常量,所以它在運行時計算一次,而不是返回每一行。因此'DATEADD(DAY,1,Column)對每一列都進行一次評估,但是每個查詢對DATEADD(DAY,1,GETDATE())'進行一次評估,因此不會對性能產生負面影響。 – GarethD

+0

我擔心的是,有些人只會聽到「**從不**」在'where子句'中使用函數。「應用於_columns_的函數可能會影響sargability。至於'GetDate()',每個_instance_是一個單獨的運行時常量,因此第一個示例中的兩個調用可以返回不同的值。 (這個功能的一些討論可以在這裏找到(https://stackoverflow.com/q/12078202/92546))。當兩個調用返回不同的日期時,試圖調試一個報表在午夜時分左右運行的僕人有點尷尬。 – HABO

0

GETDATE返回datetime,所以如果你想要比較只是日期和不在的時候,你可以使用演員。如果peSubmitDate是數據類型日期,使用該比較:

peSubmitDate = cast(GetDate() as date) 

如果它是一個DATATIME然後使用這樣的: 鑄造(peSubmitDate如日期)=流延(GETDATE()作爲日期)

的後者給出的性能更差,所以只有在日期時間才使用這個

+0

多虧了你們兩個,一個問題 - 我怎麼可以在一個SP這個SELECT語句peSubmitDate條款和另一個合併一般(沒有日期條款)? – koda5