SQL Server 如何处理日期格式 YYYY-MM-DD


问题 我最近做了一个涉及 T-SQL 的演讲,其中一个热门话题总是日期格式。我们讨论了 SQL Server 如何根据用户的语言设置处理各种日期格式。SQL Server 有时会出现这种“错误”——甚至YYYY-MM-DD是大端和据称安全的 ISO-8601 格式——让很多人感到惊讶。我之前 在这里讨论过,但让我们深入挖掘一下。

解决方案 当我第一次看到 SQL Server 误解日期时,我确信我发现了一个错误。在帮助同事编写查询时,我跳上他们的椅子并接管了他们 PC 上的查询分析器。

他们写了这样的东西:

DECLARE @d datetime;
SET @d = '2001-08-13';

他们看到了这个错误:

Převod datového typu varchar na datový typ datetime vrátil hodnotu mimo rozsah.

这翻译(好吧,粗略地)为:

The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

我查看了代码,然后又看了看消息,然后跑到我自己的办公桌前尝试重现错误。当然,它在我的电脑上运行良好。如果我每次听到那个的时候都能得到五分……

那么问题出在哪里呢? 语言。某些语言强制 SQL Server 将此特定格式解释YYYY-DD-MM为 YYYY-MM-DD. 您可以使用以下代码重现这一点:

SET LANGUAGE Czech;
GO
DECLARE @d datetime;
SET @d = '2001-08-13';

现在,您可能会问自己,哪些语言是安全的,哪些不安全?好吧,我的第一反应是:倾向于适用于所有场景的格式和方法。YYYYMMDD例如,对于所有语言的所有数据类型都是安全的。由于您无法控制某人的设置如何配置,或阻止任何应用程序发出 SET LANGUAGE命令,因此要求已知始终有效的格式会更安全。

但是您可以获得更技术性、更不合逻辑的技术性答案。SQL Server 目前支持 34 种语言,据sys.syslanguages; 尽管 文档仅列出了 33。出于某种原因, 缺少Bokmål(挪威首选的书面标准)。

您可以通过查询视图来扫描列表:

SELECT name, alias, dateformat FROM sys.syslanguages ORDER BY alias;

结果:

001.png

请注意,没有任何语言的日期格式为 ydm.

这个列表本身并不能帮助我确定哪些语言是安全的。一种方法是遍历该列表,为每个别名设置语言,然后尝试转换我多年前遇到问题的同一日期。我们可以从同一视图构建动态 SQL 命令,运行它并查看结果。

SET NOCOUNT ON;
DROP TABLE IF EXISTS #lang;
CREATE TABLE #lang(name sysname, alias sysname, success bit);
DECLARE @sql nvarchar(max) = N'DECLARE @d datetime, @success bit;';
SELECT @sql += N'
  SET LANGUAGE ' + QUOTENAME(alias) + N';
  SET @success = CASE 
    WHEN TRY_CONVERT(datetime, ''2001-08-13'') IS NULL THEN 0 ELSE 1 END;
  INSERT #lang(name,alias,success) 
    VALUES(N''' + name + ''',''' + alias + ''',@success);'
FROM sys.syslanguages;
EXEC sys.sp_executesql @sql;
SELECT success, number = COUNT(*) FROM #lang GROUP BY success;

摘要显示,在 34 种语言中,YYYY-MM-DD 在 24 种语言中是不安全的格式,仅在 10 种语言中是安全的。

002.png

我们可以通过不聚合来分解:

结果:

003.png

接下来您可能会问,为什么 SQL Server 会以这种方式运行?我希望我有一个权威的答案给你,甚至是一个合理的猜测。遗憾的是,我不太确定,尽管它可以追溯到 Sybase,甚至可以追溯到 Ahston-Tate 时代。


原文链接:https://codingdict.com/