【问题标题】:SQL WHERE DateTime is BetweenSQL WHERE DateTime 介于
【发布时间】:2015-12-22 21:44:20
【问题描述】:

我在这里有这个查询:

SELECT * 
FROM QuestionnaireAnswer 
WHERE dateCreated BETWEEN CAST('20/12/2015' AS datetime) AND CAST('22/12/2015' AS datetime)

但是我一直收到这个错误,怎么回事?以及如何解决?

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

【问题讨论】:

  • 您的服务器设置的区域设置是什么?
  • 您可能使用了错误的日期格式。你用的是什么软件?
  • 它不会是 'm/d/Y' 而不是 'd/m/Y' 吗?当我读到“超出范围的值”时,我的想法是什么

标签: sql sql-server tsql


【解决方案1】:

检查服务器上的区域设置。我敢打赌,您设置为美国日期格式,但您拥有的日期不是美国格式。

更多关于查询语言环境设置here

This SO question 有多种方法可以调整 SQL 的区域设置,包括用户调整。

如果您无权更改整个服务器的区域设置,您可以在会话 here 中更改您的区域设置。请注意,SET LANGUAGE 会自动设置 DATEFORMAT ,但您可以自行设置 set the DATEFORMAT

要对此进行测试,请尝试反转日期中的日期和月份。像这样:

SELECT * 
FROM QuestionnaireAnswer 
WHERE dateCreated BETWEEN CAST('12/20/2015' AS datetime) AND CAST('12/22/2015' AS datetime)

或者尝试将日期放在 "locale insensitive format" 中,例如 yyyymmdd HH:mm:ss.fff 。

【讨论】:

    【解决方案2】:

    SQL Server 支持多种格式 - 请参阅MSDN Books Online on CAST and CONVERT。这些格式中的大多数取决于您拥有的设置 - 因此,这些设置有时可能有效 - 有时无效。

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

    SQL Server 支持的ISO-8601 format 有两种形式:

    • YYYYMMDD 仅用于日期(无时间部分);请注意:没有破折号!,这非常重要! YYYY-MM-DD独立于 SQL Server 中的日期格式设置,并且适用于所有情况!

    或:

    • YYYY-MM-DDTHH:MM:SS 用于日期和时间 - 请注意:此格式破折号(但它们可以省略),以及固定的T 作为日期和时间之间的分隔符DATETIME 的一部分。

    这对 SQL Server 2000 和更新版本有效。在你的具体情况下,使用这个WHERE 子句:

    WHERE dateCreated BETWEEN '20151220' AND '20151222'
    

    而且您甚至不需要任何显式的 CAST 操作(或者如果您想使用显式的 CAST - 那么我建议您转换为 DATE 数据类型 - 而不是 DATETIME)。

    如果您使用 SQL Server 2008 或更新版本以及 DATE 数据类型(仅限 DATE - 不是 DATETIME!),那么您确实也可以使用 YYYY-MM-DD 格式并且也适用于 SQL Server 中的任何设置。

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

    对于 SQL Server 2008 及更高版本,如果您只需要日期部分,建议使用 DATE,如果同时需要日期和时间,则使用 DATETIME2(n)。如果可能,您应该尝试开始逐步淘汰 DATETIME 数据类型

    【讨论】:

    • 你可以有一个带有 YYYYMMDD 的时间部分。例如:“20151220 2:45 pm”或“20151220 14:45”
    • @GMastros:如果您想转换为 DATETIME(或更好:DATETIME2(n))-是的,您还可以指定我的回复中提到的时间部分:YYYY-MM-DDTHH:MM:SS(带有T 是日期和时间部分之间的固定分隔符)
    • 我想说的是,'YYYYMMDD HH:MM' 也是可以接受的,完全安全且绝对明确。
    • @GMastros:抱歉,我误解了 - 但是,是的,您的格式也很好,适用于所有欧洲语言和 DATETIME 数据类型 - 感谢您指出
    【解决方案3】:

    作为一般规则,在 SQL Server 中比较日期时不要使用特定于区域设置的格式,请使用通用 ISO 8601 格式 'yyyy/MM/dd',这样查询就变成了:

    SELECT * 
    FROM QuestionnaireAnswer 
    WHERE dateCreated BETWEEN CAST('2015/12/20' AS datetime) AND CAST('2015/12/22' AS datetime)
    

    您也可以使用特定于语言环境的格式,但您必须确保服务器上的日期格式在您的代码将连接到的所有服务器上始终保持相同。

    【讨论】:

    • 如果你想转换为 DATE,你的字符串文字很好 - 但要转换为 DATETIME,这不会总是有效 - 这仍然取决于设置 - 你需要对于DATETIME,使用YYYYMMDD根本没有破折号)是完全安全的。只需尝试SET LANGUAGE German,然后运行SELECT CAST('2015/12/20' AS datetime),您就会看到一条漂亮的红色错误消息...
    • 谢谢我不知道,我从来没有真正遇到过斜线失败的情况,从现在开始我会记住这一点。
    • 几乎所有的欧洲语言(甚至 英式英语!)都会失败 - 但只能与 DATETIME 结合使用 - 因为这只是一个日期,我会更确切地说只是单独投射到DATE
    • 知道为什么这些语言环境不允许使用斜杠吗?它们有什么特殊含义还是只是一种文化规则?
    • 当您的字符串文字中有斜杠时,非美国语言环境似乎将日期解释为 yyyy/dd/MM,因此您的 2015/12/20 是 2015 年第 20 个月的第 12 天(错误!) ...
    【解决方案4】:

    使用CONVERT,您可以编写类似的内容:

    SELECT * 
    FROM QuestionnaireAnswer 
    WHERE
    dateCreated BETWEEN CONVERT(datetime, '20/12/2015', 103)
    AND CONVERT(datetime, '22/12/2015', 103);
    

    【讨论】:

      【解决方案5】:

      如果列是日期字段,那么您应该这样做:

      SELECT * 
      FROM QuestionnaireAnswer 
      WHERE dateCreated BETWEEN TO_DATE('20-DEC-2015') AND TO_DATE('22-DEC-2015')
      

      可能并非 100% 准确,具体取决于架构和配置。

      【讨论】:

      • to_date 用于 oracle,而不是 MS SQL:connectsql.com/2011/04/…
      • 他根本没有提到微软。
      • 标记为sql-server,即Microsoft SQL Server
      • 我已经纠正了我没有看到标签,我是社区的菜鸟,但为了澄清一下,我确实说过“可能不是 100% 准确,具体取决于架构和配置。”其中涵盖了 Microsoft / Oracle 的差异。
      • 没问题,如果你不确定一个标签代表什么,你可以将鼠标悬停在它上面查看它的描述。
      猜你喜欢
      • 2022-07-26
      • 1970-01-01
      • 2015-05-09
      • 1970-01-01
      • 2021-04-05
      • 2016-09-30
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      相关资源
      最近更新 更多