我希望在执行查询时获得上个月的最后日期(无论是30
还是31
)和时间到最后一秒。
的 EG。 11/30/2015 11:59:59 PM
所以我有一个像
这样的查询SELECT DATEADD(ss, (60*60*24)-1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), -1))
它解决了我的问题。但是,当我更改DATEDIFF
部分并将0
替换为1
时,上面的查询与下面的查询之间有什么区别?
SELECT DATEADD(ss, (60*60*24)-1, DATEADD(MONTH, DATEDIFF(MONTH, 1, GETDATE()), -1))
这两个查询在运行时是否会提供相同的结果,或者我应该将其视为永久解决方案?
答案 0 :(得分:2)
不要这样做;试图获得上个月最后一天的“最后一秒”
我在假设您尝试使用BETWEEN的情况下做出这个大胆的陈述,并且您关注的是这样的准确性:
select sum(value) from Atable
where [Adate] BETWEEN '20151201' AND '21051231 59:59:59'
但是,通过使用下个月的第一天,可以轻松解决在任何月份的最后一天到达最后一个时间点的复杂性。您还需要做的就是放弃使用BETWEEN。像这样:
select sum(value) from Atable
where [Adate] >= '20151201' and [Adate] < '21060101'
少于“本月的第一天”
这就是你解决难题的方法。
&安培;顺便说一下:smalldatetime,datetime和datetime2的精度(准确度)都有所不同,更不能使用BETWEEN。
在http://sqlmag.com/t-sql/t-sql-best-practices-part-2
上查看“小心舍入错误。”具体来说,这样做:
DateLogged&lt; SELECT DATEADD(月,DATEDIFF(月,0,GETDATE()),0)
对于date,smalldatetime,datetime和datetime2列,这将是100%准确。
这是另一种尝试来解释为什么[the_next_day_at_00:00:00 + 0000000]是准确的并且使用22:59:59是不准确的。请注意样本数据的准确性
MS SQL Server 2014架构设置:
查询1 :
DECLARE @Tbl TABLE
( [ID] int identity(1,1)
, [DT_a] datetime
, [DT_b] datetime
, [DT_c] datetime2
)
INSERT INTO @Tbl
([Dt_a], [Dt_b], [Dt_c])
VALUES
(
'20151231 23:59:59'
, '20151231 23:59:59.997'
, '20151231 23:59:59.9999999'
)
select
'where [DT_b] <= 20151231 23:59:59' as FilterString
, max([Dt_a]) as [Dt_a]
, max([Dt_b]) as [Dt_b]
, max([Dt_c]) as [Dt_c]
from @Tbl
where [DT_b] <= '20151231 23:59:59'
UNION ALL
select
'where [DT_b] < 20160101'
, max([Dt_a]) as [Dt_a]
, max([Dt_b]) as [Dt_b]
, max([Dt_c]) as [Dt_c]
from @Tbl
where [DT_b] < '20160101'
<强> Results 强>:
| FilterString | Dt_a | Dt_b | Dt_c |
|-----------------------------------|----------------------------|----------------------------|-----------------------------|
| where [DT_b] <= 20151231 23:59:59 | (null) | (null) | (null) |
| where [DT_b] < 20160101 | December, 31 2015 23:59:59 | December, 31 2015 23:59:59 | 2015-12-31 23:59:59.9999999 |
数据准确性
为避免因时间单位舍入而导致的错误,请勿使用&lt; = 23:59:59
而是使用少于[the_next_day]
AND,因此避免在日期范围内使用BETWEEN。
答案 1 :(得分:0)
有关如何在SQL Server中使用或应该使用DATEDIFF的信息,请参阅此link。第二个参数,在你的情况下似乎没有区别的那个,应该是从结束日期(getdate())中减去的起始日期,以获得差异,然后转换为月份。我会尝试以典型的方式使用此功能并提供正确的开始日期。
以下是获得相同结果的另一种方法
SELECT DATEADD(ss, -1, '01/' + CONVERT(VARCHAR, DATEPART(MONTH, getdate())) + '/' + CONVERT(VARCHAR, DATEPART(YEAR, getdate())));
答案 2 :(得分:0)
这是因为DATEDIFF( MONTH, 0, GETDATE())
功能
如果您使用整数作为第二个参数,则无论您在1900-01-01
函数中使用的Interval如何,都会将其解释为datediff
以来的天数。
例如:
SELECT YEAR(0), MONTH(0), DAY(0);
year month day 1900 1 1
现在,如果我在年,月,日递增0到1
SELECT YEAR(1), MONTH(1), DAY(1);
year month day 1900 1 2
现在,如果我将值增加到365,
SELECT YEAR(365), MONTH(365), DAY(365);
year month day 1901 1 1
你可以看到年份增加了1。
有很多方法可以找出上个月的最后一个日期。这是我正在使用的那个。
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
答案 3 :(得分:0)
嗯,可以预期的是,如果将当前月份的第一天减去一毫秒,就会得到上个月的最后一个毫秒,但是如果使用datediff毫秒,-1仍然会得到第一个月的最后一个毫秒,这是行不通的您必须在月份的第几天执行datediff毫秒,-2才能达到997毫秒,而无法获得999或998。(不使用文本)。
select dateadd(MILLISECOND,-2,dateadd(month, datediff(month, 0, getdate()), 0))
您会得到2020-01-31 23:59:59.997