2017-06-25 63 views
0

我們有一個接收4個變量並返回一個int結果的函數。 我們希望將這個函數用於表格中的每個記錄,而這4個變量是從每個記錄中提取的。如何求和sql中的循環中的函數?

我該如何解決?

我的功能:

CREATE FUNCTION dbo.occupiedDaysPerListingFunction(@CheckIn date, @CheckOut date, @Email varchar(80), @Title varchar(50)) 
      RETURNS int 
    AS 
    BEGIN 
    DECLARE @nightsInRange int 
    select @nightsInRange= (CASE 
    WHEN DATEDIFF(day,@CheckIn,getdate()) >0 and DATEDIFF(day,@CheckOut,getdate())+100 <0 THEN 100 
    WHEN DATEDIFF(day,@CheckIn,getdate()) >0 and DATEDIFF(day,@CheckOut,getdate())+100 >0 THEN DATEDIFF(day,getdate(),@CheckOut) 
    WHEN DATEDIFF(day,getdate(),@CheckIn) >0 and DATEDIFF(day,getdate(),@CheckIn) <100 and DATEDIFF(day,@CheckOut,getdate())+100 >0 THEN DATEDIFF(day,@CheckIn,@CheckOut) 
    WHEN DATEDIFF(day,getdate(),@CheckIn) >0 and DATEDIFF(day,getdate(),@CheckIn) <100 and DATEDIFF(day,@CheckOut,getdate())+100 <0 THEN DATEDIFF(day,@CheckIn,getdate())+100 
    WHEN DATEDIFF(day,@CheckIn,getdate()) <0 THEN 0 
END) 
FROM [dbo].[ORDERS] o 
     WHERE o.[E-mail] = @Email and o.[title][email protected] 
     RETURN @nightsInRange 
end 

enter image description here

+0

您的問題的標題提到「總和」,但沒有出現在問題中。爲什麼不? – HABO

回答

0

光標就是適合這個任務的工具。 Сursor是可能的選擇之一。你也可以使用一個while循環,熱膨脹係數等

DECLARE @iterator CURSOR 
DECLARE @bufferTable TABLE 
(
    CheckIn date, 
    CheckOut date, 
    Email varchar(80), 
    Title varchar(50) 
) 

SET @iterator = CURSOR FOR 
SELECT 
    CheckIn, 
    CheckOut, 
    Email, 
    Title 
FROM [YourDatabase].[YourSchema].[YourTable]  

OPEN @iterator 

FETCH NEXT FROM @iterator 
INTO @bufferTable 

WHILE @@FETCH_STATUS = 0 
BEGIN 

    /* Your function comes into play */ 
    dbo.occupiedDaysPerListingFunction(@bufferTable.CheckIn, @bufferTable.CheckOut, @bufferTable.Email, @bufferTable.Title) 

    FETCH NEXT FROM @iterator 
    INTO @bufferTable 
END; 

CLOSE @iterator 
DEALLOCATE @iterator 

GO 

編輯:

基於@Rasmus Dybkjær的回答,您可以縮小這樣的SELECT查詢:

SELECT InnerQueryTable.OccupiedDaysPerListing FROM 
(
    SELECT 
     CheckInDate, 
     CheckOutDate, 
     Email, 
     Title, 
     dbo.occupiedDaysPerListingFunction(CheckInDate, CheckOutDate, Email, Title) AS OccupiedDaysPerListing 
    FROM 
     [YourDatabase].[YourSchema].[YourTable] 
) AS InnerQueryTable 
GO 
0

我會開始確保你的函數總是返回一個整數。您當前的功能通過電子郵件和標題上的過濾器向您的[訂單]表發送查詢。您應該考慮如果您的[訂單]表格包含具有相同電子郵件和標題的多行,會發生什麼情況。

我會重寫你的函數是這樣開始:

CREATE FUNCTION dbo.occupiedDaysPerListingFunction(@CheckIn DATE, @CheckOut 
DATE, @Email VARCHAR(80), @Title VARCHAR(50)) 
RETURNS INT 
AS 
BEGIN 
    DECLARE @nightsInRange INT = 0; 
    SET @nightsInRange = (SELECT TOP 1 CASE 
     WHEN DATEDIFF(day,@CheckIn,getdate()) >0 and  DATEDIFF(day,@CheckOut,getdate())+100 <0 THEN 100 
     WHEN DATEDIFF(day,@CheckIn,getdate()) >0 and  DATEDIFF(day,@CheckOut,getdate())+100 >0 THEN DATEDIFF(day,getdate(),@CheckOut) 
     WHEN DATEDIFF(day,getdate(),@CheckIn) >0 and  DATEDIFF(day,getdate(),@CheckIn) <100 and DATEDIFF(day,@CheckOut,getdate())+100  >0 THEN DATEDIFF(day,@CheckIn,@CheckOut) 
     WHEN DATEDIFF(day,getdate(),@CheckIn) >0 and  DATEDIFF(day,getdate(),@CheckIn) <100 and DATEDIFF(day,@CheckOut,getdate())+100  <0 THEN DATEDIFF(day,@CheckIn,getdate())+100 
     WHEN DATEDIFF(day,@CheckIn,getdate()) <0 THEN 0 
     ELSE 0 
    END 
    FROM [dbo].[ORDERS] o 
    WHERE o.[E-mail] = @Email and o.[title][email protected]) 

    RETURN @nightsInRange 
END 

此功能還不夠完美無瑕,但它可以確保: 1)你的功能在所有情況下返回一個值(即使沒有記錄發現) 2)你的功能不相同的電子郵件和標題失敗的原因多[常規]

以後我會叫你的函數從這樣的查詢:

SELECT 
    CheckInDate, 
    CheckOutDate, 
    Email, 
    Title, 
    dbo.occupiedDaysPerListingFunction(CheckInDate, CheckOutDate, Email,  Title) AS OccupiedDaysPerListing 
FROM 
    [YourDatabase].[YourSchema].[YourTable] 

希望有所幫助。

+0

通常'TOP'應該與'ORDER BY'配對。在這種情況下,任何行都可以做,值得添加註釋來解釋預期的行爲。請注意,GetDate()的每個實例將爲所有行返回單個值,但不同的實例可能會返回不同的值。最佳實踐是獲得單個值,例如'聲明@Now爲DateTime = GetDate();',並在函數的其餘部分使用變量'@ Now'。 – HABO

+0

同意你的觀點,@HABO。這些將是對查詢的額外改進。在這種情況下,他很可能要按訂單日期降序訂購。即 'ORDER BY [OrderDate] DESC' – dybzon