2017-06-25 61 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