SQL-日期查询问题-varchar到datetime的转换导致值超出范围

SQL-日期查询问题-varchar到datetime的转换导致值超出范围,sql,tsql,datetime,sql-server-2008-r2,Sql,Tsql,Datetime,Sql Server 2008 R2,我有一个SQL查询,是由一位不在这里的同事编写的。查询作为SSIS作业的一部分运行,从本月起已开始失败,出现以下错误: 将varchar数据类型转换为datetime数据类型导致值超出范围 查询本身只是一个基本的选择,带有where子句,用于查找特定时间范围内的值(介于@startdate和@enddate之间的日期范围) 确定时间范围的代码如下所示: DECLARE @RunDateTime datetime DECLARE @RunDate datetime DECLARE

我有一个SQL查询,是由一位不在这里的同事编写的。查询作为SSIS作业的一部分运行,从本月起已开始失败,出现以下错误:

将varchar数据类型转换为datetime数据类型导致值超出范围

查询本身只是一个基本的选择,带有where子句,用于查找特定时间范围内的值(介于
@startdate
@enddate
之间的日期范围)

确定时间范围的代码如下所示:

DECLARE     @RunDateTime datetime
DECLARE     @RunDate datetime
DECLARE     @StartDate datetime
DECLARE     @EndDate datetime
DECLARE     @Month int
DECLARE     @Year int
DECLARE     @strStartDate varchar(10)

SET     @RunDateTime = GetDate()
SET     @RunDate = cast(round(convert(real, @RunDateTime),0,1) as datetime)

IF                  DATEPART(d, @RunDate) = 16
    BEGIN       
                    SET @StartDate =  DATEADD(d, -15, @RunDate)
                    SET @EndDate = @RunDate
    END
ELSE
    BEGIN
                    IF      Month(@RunDate) = 1
                            SET @Month = 12
                    ELSE    
                            SET @Month = Month(@RunDate) - 1

                    IF      Month(@RunDate) = 1
                            SET @Year = Year(@RunDate) - 1
                    ELSE
                            SET @Year = Year(@RunDate)

                    SET @strStartDate = CONVERT(varchar(2), @Month)+ '/16/' + CONVERT(varchar(4), @Year)
                    SET @StartDate = CONVERT(datetime, @strStartDate, 101)
                    SET @EndDate = @RunDate
    END
这项工作每月运行两次。本月1日至15日的数据为16日一次,下个月1日的数据为16日至上个月底一次

从我在网上找到的资料来看,使用
varchar
表示
strStartDate
很可能是罪魁祸首?我对SQL不够熟悉,不知道如何替换那里正在进行的所有转换工作?另外,有没有比只获取运行时间更好的方法来确定月末日期?任何帮助都将不胜感激


(顺便说一句,我们在SQL Server 2008 R2上运行此作业)我与DBA进行了检查,他没有说SQL Server上的本地化或区域设置已更改。

SQL Server支持多种格式-请参阅。大多数格式取决于您的设置,因此,这些设置有时可能有效,有时无效

解决此问题的方法是使用SQL Server支持的(稍作调整的)ISO-8601日期格式,无论您的SQL Server语言和日期格式设置如何,此格式始终有效

SQL Server支持的有两种风格:

  • YYYYMMDD
    仅适用于日期(无时间段);注意:无破折号,这非常重要
    YYYY-MM-DD
    独立于SQL Server中的日期格式设置,在所有情况下都将工作
或:

  • 日期和时间的
    YYYY-MM-DDTHH:MM:SS
    -此处注意:此格式有破折号(但可以省略),并且在
    DATETIME
    的日期和时间部分之间有一个固定的
    T
    分隔符
这对SQL Server 2000及更新版本有效

如果您使用SQL Server 2008或更高版本以及
日期
数据类型(仅
日期
-
日期时间
!),那么您确实也可以使用
YYYY-MM-DD
格式,这也适用于SQL Server中的任何设置

另外:对于SQL Server 2008,建议尽可能使用
DATETIME 2
(而不是
DATETIME
)<代码>日期时间2字符串解析对于错误和/或不同格式(如美国AM/PM格式等)更为宽容


不要问我为什么这个话题如此棘手,有些令人困惑——事实就是这样。但是使用
YYYYMMDD
格式,您应该可以使用任何版本的SQL Server以及SQL Server中的任何语言和日期格式设置。

看起来您正在尝试计算上月16日。与其进行字符串操作,不如尝试
SET@StartDate=DATEADD(month,DATEDIFF(month,'20010101',@RunDate),'20001216')
,它应该总能找到它(保持两个字符串常量完全相同)。您确定错误在发布的代码部分吗?转换行上的101(datetime,@strStartDate,101)表示strStartDate应为mm/dd/yyyy格式,因此这不应取决于服务器的区域设置。@Damien_不相信者是的,此查询将始终在一个月的第一个月和第十六个月运行。如果它不是在一个月的第16天运行,那么它必须是第1天,因此我们希望StartDate值表示上个月的第16天。(如果查询在1号运行,我们基本上只想得到上个月的第16天)我不太懂SQL,但是您提供的代码在任何月份都有效吗?或者只在12月份做?@Oryx-是的,它在任何月份都有效。基本上,它计算2001年1月1日到
@RunDate
之间发生了多少个月。然后在2000年12月16日之前加上相同的月份数。仔细想想,它应该总是产生
@RunDate
前一个月的第16个。如果startdate是varchar类型并且具有无效值,则查询的其余部分可能出错。如果您有权直接运行sql查询,我会尝试从xxx运行
SELECT Count(*),其中startdate介于“20121216”和“20130101”之间
,以查看它是否会生成错误。此外,您还可以运行“代码关于”部分并添加一些选项,例如,
Select@strStartDate
Select@StartDate
来查看它在做什么。感谢您提供了如此全面的答案。我正在阅读这些链接,但我想我不太确定如何修改我发布的SQL的实际方面。我是否只是将strStartDateTime参数更改为datetime2?如果是这样的话,我是否必须重做查找本月16日的逻辑,因为它似乎依赖于该参数为varchar?对不起,如果这些是哑巴?s@Oryx:如果您需要构造一个字符串来解析为
DATETIME
,我只需确保使用其中一种安全格式-因此请替换此:
SET@strStartDate=CONVERT(varchar(2),@Month)+'/16/'+CONVERT(varchar(4),@Year)
类似于这样的内容:
YYYYMM16
然后转换-这是一种安全且独立于语言的格式,转换总是很好。@Oryx:如果需要构造日期的字符串表示形式,请使用安全格式,例如2013年1月16日构造
20130116
,然后解析