【问题标题】:Sql Server strict convert from varchar to datetimeSql Server 从 varchar 严格转换为 datetime
【发布时间】:2011-02-24 17:50:44
【问题描述】:

我在 Sql Server 2005 中将 varchar 转换为 datetime。如果提供的 varchar 具有意外格式,我可以强制 Sql Server 失败吗?

例子:

select convert(datetime, '01-2010-02', 103) 

预期结果:查询失败,因为 103 表示 dd/mm/yyyy(请参阅msdn)。

实际结果:2010-02-01 00:00:00.000

请求执行的主要目的是按日和月的顺序。如果 varchar 以 yyyy-mm-dd 格式提供,则由于提供格式 (dd/mm/yyyy) 的日/月顺序,Sql Server 会将 mm 视为日,将 dd 视为月。

注意:我可以编写自定义函数来手动处理这种情况。但我希望这样的企业数据库已经可以严格处理数据。

【问题讨论】:

  • 如果你可以只使用“安全”的日期时间格式会更容易——当转换为日期时间时,SQL Server 永远不会出错的三种格式,你不需要提供格式参数.日期(没有时间组件)是yyyymmdd,没有分隔符。

标签: sql-server sql-server-2005 datetime strict


【解决方案1】:

恐怕您必须使用CLR Function 并利用DateTime.TryParseExact 方法。不是一个优雅的解决方案,但可以工作。

【讨论】:

    【解决方案2】:

    您可以将日期与转换为日期时间的数据进行比较,然后再返回。我不确定这样做是否有任何陷阱,但我有限的测试没有发现任何陷阱。

    if @StrDate = convert(varchar(10), convert(datetime, @StrDate, 103) ,103)
    

    【讨论】:

    • 我相信可以有,例如,如果原始字符串没有前导零,比如24/2/2011
    • @Andriy 你是对的。但只有在没有前导零是可接受的情况下,我想这取决于它在世界上的哪个地方使用。我来自哪里不好。如果两者都应该被允许,你必须做一些字符串操作,在比较之前插入零。
    • 有了 Sql Server 的这些惊喜,我最好手动检查提供的字符串的格式: if(@StrDate like '[0-9][0-9]/[0-1][0- 9]/[0-9][0-9][0-9][0-9]')
    • @Vladimir 除了允许像 99/99/9999 这样的日期,即使您将天数限制为 31,您也可以获得 31/02/2009(2 月无效)
    【解决方案3】:

    只要 SQL Server 看到明确的 Year 候选者,它将始终用作 Year。

    剩余的 DM 部分由 DMY 设置或转换格式中的顺序确定。如果不是这样,那么非常简单的转换就会失败。

    例子

    set dateformat dmy
    select 1 a,CONVERT(datetime, '1-2-3') b
    union all
    select 2,CONVERT(datetime, '2001-2-3')
    union all
    select 3,CONVERT(datetime, '2001-3-2')
    

    输出

    a           b
    ----------- -----------------------
    1           2003-02-01 00:00:00.000
    2           2001-03-02 00:00:00.000
    3           2001-02-03 00:00:00.000
    

    第 2 和第 3 明确地将年份放在前面,那是 ok


    编辑

    Books Online 有这个说法http://msdn.microsoft.com/en-us/library/ms180878.aspx#StringLiteralDateandTimeFormats

    SET DATEFORMAT 有很多例外,无论转换的第三个参数如何,它都会起作用。

    • SET DATEFORMAT 会话设置不适用于全数字日期条目
    • 此 [ISO 8601] 格式不受登录默认语言设置的 SET DATEFORMAT、SET LANGUAGE 影响。
    • 当您以字母形式指定月份时,不会应用 SET DATEFORMAT 会话设置。

    要专门验证 dd/mm/yyyy,请改用以下代码

    set dateformat dmy
    declare @input varchar(10) set @input = '12-2010-01'
    
    -- convert allows the date through
    select convert(datetime, @input, 103) -- 2010-01-12 00:00:00.000
    
    -- the case below returns 0 { = invalid date }
    -- this uses 8-digit format which is always interpreted YYYYMMDD regardless
    -- of language or dateformat settings
    select case
        when @input not like '__/__/____' then 0
        else isdate(right(@input,4)+right(left(@input,5),2)+left(@input,2))
        end
    

    【讨论】:

    • 'Set dateformat dmy' 适用于 dd/mm/yyyy,但在 yyyy-mm-dd 的情况下,日期和月份将被静默交换。这就是为什么我要强制格式化。我知道预期格式的日期和月份顺序,但我不知道任何其他格式的顺序。
    猜你喜欢
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    相关资源
    最近更新 更多