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 给我带来了麻烦的主要内容,如果未能解决你的问题,请参考以下文章