SQL 计算的问题 - datediff 给我带来了麻烦

Posted

技术标签:

【中文标题】SQL 计算的问题 - datediff 给我带来了麻烦【英文标题】:Trouble with TSQL calculation - date diff giving me troubles 【发布时间】:2015-07-09 07:15:38 【问题描述】:

我得到了这个函数的正确输出。 datediff 是否仅计算同一个月内天数的差异? 当我以“2015 年 1 月 1 日”的形式传递一个日期时,它总是给我发回一个 0 =/我是否错过了我的逻辑或语法中的某些内容?

CREATE FUNCTION dbo.CanPolicy
(
    @ReservationID int,
    @CancellationDate date
)
RETURNS smallmoney
AS
    BEGIN
        DECLARE @DepositPaid smallmoney
        SET @DepositPaid = (SELECT ResDepositPaid
                            FROM Reservation
                            WHERE ReservationID = @ReservationID)
        DECLARE @ResDate date
        SET @ResDate = (SELECT ResDate
                        FROM Reservation
                        WHERE ReservationID = @ReservationID)
        DECLARE @CanceledDaysAhead int
        SET @CanceledDaysAhead = DATEDIFF(day, @ResDate, @CancellationDate)
        DECLARE @result smallmoney
        SET @result = 0
        SET @result = CASE WHEN @CanceledDaysAhead > 30 THEN 0
                        WHEN @CanceledDaysAhead BETWEEN 14 AND 30 THEN @DepositPaid * 0.25 + 25
                        WHEN @CanceledDaysAhead BETWEEN 8 AND 13 THEN @DepositPaid * 0.50 + 25
                        ELSE @DepositPaid
                    END
        RETURN @result
    END

GO

【问题讨论】:

你说@CancellationDate = 01 Jan 2015时出错,请指定ResDate的值,用于计算.. 不知道测试场景的所有参数,但是我觉得datediff参数需要切换:DATEDIFF(day, @CancellationDate, @ResDate)否则如果cancellationdate在reservationdate之前,datediff会一直返回负值,使得case 结果不正确。 另外附注,您可以一次性获得预付和重订日期:SELECT @DepositPaid = ResDepositPaid, @ResDate = ResDate FROM Reservation WHERE ReservationID = @ReservationID @Me.Name Jake 所做的是正确的,因为Select 语句是非标准的赋值语句。如果给定的ReservationID 有两个ResDate,那么通过Select 进行分配不会引发任何错误,并且只会分配两个限定值中的任何一个。虽然通过Set 分配会引发错误,因此我们可以确定应该选择两个ResDate @Me.Name,不错的收获! DATEDIFF 中的值的切换做到了。看起来我需要仔细检查我的阅读,阅读 DATEDIFF 的文档是我做的第一件事,我发誓它是从左边减去右边的值,而不是从右边减去左边的值。 【参考方案1】:

不,DATEDIFF 计算介于两者之间的日期。试试:

SELECT DATEDIFF(day,ts'2105-01-01 00:00:00',ts'2105-04-01 00:00:00')

可能是日期格式问题...

您确定@ResDate 设置正确吗?

编辑:CTE 的新方法

DECLARE @ReservationID INT=123;
DECLARE @CancelationDate DATE=GETDATE();

WITH ReservationCTE AS
(
    SELECT ResDepositPaid 
          ,ResDate
    FROM Reservation
    WHERE ReservationID=@ReservationID --assuming that ReservationID is a unique key!
)
,ReservationCTEWithDateDiff AS
(
    SELECT ReservationCTE.*
          --EDIT: switched dates due to a comment by Me.Name
          ,DATEDIFF(DAY,@CancelationDate,ResDate) AS CanceledDaysAhead
    FROM ReservationCTE
)
SELECT CASE WHEN CanceledDaysAhead>30 THEN 0
            WHEN CanceledDaysAhead BETWEEN 14 AND 30 THEN ResDepositPaid * 0.25 + 25
            WHEN CanceledDaysAhead BETWEEN 8 AND 13 THEN ResDepositPaid * 0.50 + 25
            ELSE ResDepositPaid END AS MyReturnValue
FROM ReservationCTEWithDateDiff

【讨论】:

@ResDate 从我的数据库中的选择中获取一个值作为“日期”。如果日期是相同的数据类型,一般日期是否以相同的格式存储日期?或者,例如,如果有两个日期,与 DATEDIFF 相比,它们是否可以以不同的方式存储并发生冲突?编辑:添加逗号以使我的问题更容易理解。编辑:如果 工作正常,将通知您连接到我的远程数据库时遇到问题。不要忽略您的想法输入=) 我给了你另一种性能更好的方法(特别是如果“预订”充满了很多行......试一试......如果有帮助请投票谢谢 它不会让我投票。我是这里的新手,呃,但我会记得在我达到 15 岁时回来并支持它。如果那是理所当然的事情!再次感谢您的周到意见!【参考方案2】:

我认为您的函数的正确和简短版本是这样的 - 请试一试:

CREATE FUNCTION dbo.CanPolicy
(
    @ReservationID int,
    @CancellationDate date
)
RETURNS smallmoney
AS
    BEGIN
        DECLARE @DepositPaid smallmoney,
                @CanceledDaysAhead int

        SELECT  @DepositPaid = ResDepositPaid,
                @CanceledDaysAhead = DATEDIFF(DAY,ResDate,@CancellationDate)
        FROM    Reservation
        WHERE   ReservationID = @ReservationID


        RETURN CAST(CASE WHEN @CanceledDaysAhead > 30 THEN 0 ELSE
               CASE WHEN @CanceledDaysAhead BETWEEN 14 AND 30 THEN @DepositPaid * 0.25 + 25 ELSE
               CASE WHEN @CanceledDaysAhead BETWEEN 8 AND 13 THEN @DepositPaid * 0.50 + 25 ELSE
               @DepositPaid END END END AS smallmoney)

    END
GO

主要问题是您的情况-我认为何时阻止...

【讨论】:

问题最终是 DATEDIFF,尽管我是 SQL 新手。为每个“WHEN”添加“END”是最佳做法吗? CASE WHEN <expression> THEN <truepart> ELSE <falseparte> END【参考方案3】:

您现在可能已经解决了这个问题,但是我处理日期差异的一种方法是使用 ABS:

ABS on MSDN

这样case语句就不需要区分它们了。

【讨论】:

以上是关于SQL 计算的问题 - datediff 给我带来了麻烦的主要内容,如果未能解决你的问题,请参考以下文章

SQL中基于datediff和curdate函数计算列值

SQL中计算时间差datediff()

T-SQL 计算两天之间的天数(datediff 不太有效)

sqlserver日期计算的问题

SQL时间处理datediff的问题

SQL Server DATEDIFF() 函数