带有 French_CI_AS 排序规则日期转换的 SQL Server

Nir*_*ava 4 collation type-conversion datetime localization sql-server-2016

我有一个使用French_CI_AS排序规则的 SQL Server 法语安装。出于遗留原因,表列将数据存储VARCHAR为稍后转换为正确类型的数据,类似于 C++ 中的变体。

此列中的两行数据如下:

2020-10-12 22:54:40

2020-10-13 04:42:10
Run Code Online (Sandbox Code Playgroud)

DATETIME使用默认选项转换为时,第二个日期失败。该应用程序使用 ODBC 转义序列。SQL 等COLMVALUE >= {ts'2020-01-01 00:00:00'}失败并显示错误:

La Conversion d'un type de données nvarchar en type de données datetime a créé une valeur hors limites

我做了一个DBCC useroptions ,服务器的日期格式设置为dmy. 为什么第 2 行失败?看起来它试图将“13”解释为月份。如果格式是dmy,两个日期不应该都失败吗?

此外,有趣的是,在此服务器上,以下失败:

2020-10-12 22:54:40

2020-10-13 04:42:10
Run Code Online (Sandbox Code Playgroud)

但这有效:

DECLARE @datevar DATETIME = '2020-10-13 04:42:10';    
SELECT @datevar;  
Run Code Online (Sandbox Code Playgroud)

我知道这DATETIME2DATETIME. 但是,这里的两者似乎连解析都不一样。

Sol*_*zky 7

这不是整理问题。这是一个语言/地区/文化问题。您的数据库(或您登录的默认语言)设置为“法语”(最有可能),并且他们使用日后月格式,而不是月后日,因此您的声明试图使用第 13 个月。

试试这个来重现:

SET LANGUAGE French;
DECLARE @datevar DATETIME = '2020-10-13 04:42:10';
/*
Le paramètre de langue est passé à Français.
Msg 242, Level 16, State 3, Line XXXXX
La conversion d'un type de données varchar en type de données datetime a
    créé une valeur hors limites.
*/

GO
PRINT '-----';
GO

SET LANGUAGE English;
DECLARE @datevar DATETIME = '2020-10-13 04:42:10';
GO
Run Code Online (Sandbox Code Playgroud)

您有两种更改方式:

  1. SET LANGUAGE
    此控制不只是日期格式,而且货币符号,日期和月份的名称等,这可能不是因为它控制不仅仅是日期格式的最佳选择,但它可能会,如果只需要更新更容易登录的默认语言,而不是更新大量代码来执行选项 #2。

  2. SET DATEFORMAT
    这仅控制日期格式:

    SET LANGUAGE French;
    DECLARE @datevar DATETIME = '2020-10-13 04:42:10';
    /*
    Le paramètre de langue est passé à Français.
    Msg 242, Level 16, State 3, Line XXXXX
    La conversion d'un type de données varchar en type de données datetime a
        créé une valeur hors limites.
    */
    
    SET DATEFORMAT ymd;
    DECLARE @datevar2 DATETIME = '2020-10-13 04:42:10';
    
    SELECT @datevar AS [@datevar], @datevar2 AS [@datevar2];
    /*
    @datevar    @datevar2
    NULL        2020-10-13 04:42:10.000
    */
    
    Run Code Online (Sandbox Code Playgroud)

 
关于您的其他问题:

如果格式是dmy,两个日期不应该都失败吗?

(暗示)为什么DATETIMEDATETIME2似乎对同一日期的解析不同?

所有这一切都是因为处理日期真的很混乱。的文档DATEFORMAT不仅说明:

datetimesmalldatetime解释可能与datedatetime2datetimeoffset不匹配

但是也:

某些字符串格式(例如 ISO 8601)的解释独立于 DATEFORMAT 设置。

虽然文件没有这两个语句绑在一起,测试确实显示,ISO 8601格式的日期(例如YYYY-MM-DD)的“独立解释DATEFORMAT设置”仅适用于DATEDATETIME2DATETIMEOFFSET。这就是为什么日期'2020-10-13'方面的价值DATEFORMAT为你的DATETIME变量(因此当一天到来前的一个月,无论是分离的日期部分收到的文化错误“ - ”或“/”),但正确地分析你的DATETIME2测试(无论 的当前文化或价值如何,都将始终如此DATEFORMAT)。

PS我不认为一个变种/ SQL_VARIANT/object等是“正确的”类型;-)