【问题标题】:SQL Server date calculations in stored procedures存储过程中的 SQL Server 日期计算
【发布时间】:2013-06-27 21:25:26
【问题描述】:

我想就以下代码提出 3 个问题(请原谅冗长的代码清单,我将这些行包括在内是希望它提供足够的上下文)。

请注意,此处的代码取决于执行日期。出于这个原因,我的问题涉及两个不同执行日期的假设情况:

  1. 2014 年 3 月 1 日
  2. 2014 年 1 月 1 日

我的问题是我对其中某些部分的理解是否正确,即:

一个SELECT DATEADD 表达式(在第 1 行)将:

  • 2014 年 3 月 1 日 创建日期时间 2014-02-31 23:59:59

B。第 6-9 行的代码将:

  • 2014 年 3 月 1 日 创建日期时间 2014-02-01 00:00:00
  • 2014 年 1 月 1 日 创建日期时间 2013-02-01 00:00:00

C。第 11-14 行的代码将:

  • 2014 年 3 月 1 日 创建日期时间 2015-01-30 00:00:00
  • 2014 年 1 月 1 日 创建日期时间 2014-01-30 00:00:00

这种理解正确吗?

1. SET @ldpmth = (SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)) )
2. SET @yr = (SELECT YEAR(@ldpmth))
3. SET @mth = 0
4. SET @dy = 0
5. 
6. SET @fysdate = (SELECT CASE WHEN MONTH(@ldpmth) >= 2 THEN
7. DATEADD(MM, 1,CAST(CAST(@yr+@mth+@dy AS NVARCHAR(50)) AS DATETIME))
8. ELSE DATEADD(MM, 1, CAST(CAST((@yr-1)+@mth+@dy AS NVARCHAR(50))
9. AS DATETIME)) END ) 
10. 
11. SET @fyedate = (SELECT CASE WHEN MONTH(@ldpmth) >= 2 THEN
12. DATEADD(YY, 1, CAST(CAST(@yr+@mth+@dy AS NVARCHAR(50)) AS DATETIME)) + 30
13. ELSE  DATEADD(YY, 1, CAST(CAST((@yr-1)+@mth+@dy AS NVARCHAR(50))
14. AS DATETIME)) + 30 END )

(感谢到目前为止所有回答的人。这实际上是几年前在我的工作地点开发(但未记录)的代码,我的任务是将其转换为可在客户端使用的表单水晶报表。)

【问题讨论】:

  • 为什么不能用2014-03-01 替换GETDATE() 并自己测试这些?
  • 问A,你做错了。您可能正在尝试捕获上个月发生的所有事情,并且您正在努力计算一个包容性端点(目前排除当天最后一分钟 x 毫秒内发生的任何事情) - 计算起来要容易得多处理 continua 时的独占上限。

标签: sql-server tsql stored-procedures


【解决方案1】:

在 2014 年 3 月 1 日创建日期时间 2014-02-31 23:59:59

没有。 AFAIK,没有 任何 dbms 如此愚蠢,以至于认为 2 月 31 日是实际日期。第 1 行的 SQL 语句将返回值 'Feb 28 2014 23:59:59'。

您可以通过用实际日期代替 GETDATE() 和猜测来测试您的所有语句。例如,在第一个查询中,使用

SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'2014-03-01'),0));
                                              ^^^^^^^^^^

您可能可以在本地运行某个版本的 SQL Server。 SQL Server 2008 甚至可以安装在 Windows XP 上。但是,如果你不能忍受,总有 sqlfiddle.com。

【讨论】:

  • @ypercube:嗯,是的。而 MS Access 过去可以让您将日历日期相乘。 (我不知道它是否仍然存在。)您可以将 2013 年 1 月 12 日的日期乘以 2014 年 2 月 17 日的日期,并得到一些数字。我猜是方形日期中的一些数字。
  • 感谢 Mike Sherrill 的回答和特别是。在本地 SQL 服务器中进行测试的提示(我安装了一个,但我在蓝月亮中使用过一次,因为 SQL 不是我日常工作任务的一部分)。 2 月 31 日的日期对我来说是一个愚蠢的错字(这就是我匆忙的结果)。
【解决方案2】:

这可以在 SQL Server Management Studio (SSMS) 中轻松测试。我会回答第一个,你可以自己测试下两个。

问题:

A. DATEADD(第 1 行)将在 2014 年 3 月 1 日创建日期时间 2014-02-31 23:59:59

回答:不,因为二月不可能有31天,所以不能返回'2014-02-31`

证明:

select DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'2014-03-01'),0))

Results

(No column name)
2014-02-28 23:59:59.000

【讨论】:

  • 感谢 Ken White 的回答以及本地测试的提示。
【解决方案3】:

对于 (B) 和 (C),如果您将问题表述为“我的财政年度从 2 月 1 日到 1 月 30 日(原文如此) - 我如何获得当前的开始和结束日期财政年度,我会提供:

SET @fysdate = DATEADD(year,DATEDIFF(month,'19000201',GETDATE())/12,'19000201')

和:

SET @fyedate = DATEADD(year,DATEDIFF(month,'19000201',GETDATE())/12,'19010131')

(请注意,这一秒找到的是 1 月 31 日,而不是 30 日。我认为这是您最初问题的粗心)。

但是,至于 (A),正如我所指出的,我认为您的问题再次措辞不当 - 如果您试图找到一个时期的结束点并且该时期是在日期时间定义的(而不是仅仅日期),构造一个独占上限要容易得多:

SET @ldpmth = DATEADD(month, DATEDIFF(month,0,GETDATE()),0)

此界限(与< 比较而不是<=BETWEEN 一起使用)不会人为地排除任何带有时间的值,例如23:59:59.527。另请注意,如果要将财政年度结束日期计算用于包含时间的日期时间值,我会再次建议计算 exclusive 上限,并用 19010201 代替 @987654329 @。

因此,总的来说,我认为我并没有真正回答你提出的问题,但我认为我已经提供了你应该寻求的答案。

【讨论】:

  • 谢谢达米安。实际上你的回答解释了我对这段代码的一些问题,虽然我不能使用它(因为我需要写一些我可以在水晶报表设计器中使用的东西)。是的,我确实看到我最初的问题至少有两个日期拼写错误(1 月 30 日和 2 月 31 日)。
猜你喜欢
  • 2021-10-06
  • 2010-09-15
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-01
  • 2014-09-04
  • 1970-01-01
相关资源
最近更新 更多