这里的危险来源是他:你依赖于你的系统文化。
文化相关的日期格式很危险(10/09/2017 是什么?是 10 月 9 日还是 9 月 10 日?)。但更糟糕的是依赖于语言的格式(在我的国家,十月是十月)。
试试这个
SET LANGUAGE ENGLISH;
SELECT TRY_CAST('January 2017' AS DATE),TRY_CONVERT(DATE,'January 2017')
SET LANGUAGE GERMAN;
SELECT TRY_CAST('January 2017' AS DATE),TRY_CONVERT(DATE,'January 2017')
没有TRY_ 的替代调用不会返回NULL,但会引发错误。
但你说的是[sql-server-2014]。这意味着you can use TRY_PARSE() (v2012+)。最大的优势:您可以指定基础文化。
SET LANGUAGE GERMAN
SELECT TRY_PARSE('January 2017' AS DATE USING 'en-us')
如果有最小的机会,您的代码可能会在国际环境中运行,您应该永远不要依赖默认文化...
更新性能与稳定性...
在评论中我回答了@SQL_M:
我知道我会选择什么...如果日期处理得当,你永远不会
不得不处理这样的问题。我们应该看到文本格式
仅输出。用户的输入应由应用程序处理
层。所以数据库永远不必考虑这样的问题
转换。这种需要存在的事实清楚地表明,
数据库/应用程序设计不正确。我们不应该添加更多
如果我们可以避免它的弱点
这让我很好奇,我做了一些测试。
我必须承认:性能差异是不可否认的,而且比预期的要大得多。在日期为Jan 1 1900 12:11AM(默认为CONVERT,参数100)的一百万行中,我得到:
- TRY_CONVERT 大约 600 毫秒
- TRY_CAST 大约 550 毫秒
- TRY_PARSE 大约 45.000 毫秒
所以是的,确实值得了解性能影响 (~x100)。但上面的说法仍然正确。
测试代码 - 如果有兴趣:
USE master;
GO
CREATE DATABASE testDB
GO
USE testDB
GO
CREATE TABLE testTbl(ID INT IDENTITY,DateString VARCHAR(100));
GO
WITH Tally(Nmbr) AS (SELECT TOP 1000000 ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) FROM master..spt_values v1 CROSS JOIN master..spt_values v2 CROSS JOIN master..spt_values)
INSERT INTO testTbl(DateString)
SELECT CONVERT(DATETIME,DATEADD(MINUTE,t.Nmbr,'19000101'),100)
FROM Tally t;
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS
GO
DECLARE @d DATETIME2=SYSUTCDATETIME();
SELECT TRY_CONVERT(DATETIME,DateString) AS d INTO t1 FROM testTbl;
SELECT 'TRY_CONVERT', DATEDIFF(MILLISECOND,@d,SYSUTCDATETIME());
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS
GO
DECLARE @d DATETIME2=SYSUTCDATETIME();
SELECT TRY_CONVERT(DATETIME,DateString,100) AS d INTO t2 FROM testTbl;
SELECT 'TRY_CONVERT with 3rd param', DATEDIFF(MILLISECOND,@d,SYSUTCDATETIME());
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS
GO
DECLARE @d DATETIME2=SYSUTCDATETIME();
SELECT TRY_PARSE(DateString AS DATETIME) AS d INTO t3 FROM testTbl;
SELECT 'TRY PARSE',DATEDIFF(MILLISECOND,@d,SYSUTCDATETIME());
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS
GO
DECLARE @d DATETIME2=SYSUTCDATETIME();
SELECT TRY_PARSE(DateString AS DATETIME USING 'de-de') AS d INTO t4 FROM testTbl;
SELECT 'TRY PARSE with culture',DATEDIFF(MILLISECOND,@d,SYSUTCDATETIME());
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS
GO
DECLARE @d DATETIME2=SYSUTCDATETIME();
SELECT TRY_CAST(DateString AS DATETIME) AS d INTO t5 FROM testTbl;
SELECT 'TRY_CAST',DATEDIFF(MILLISECOND,@d,SYSUTCDATETIME());
GO
USE master;
GO
DROP DATABASE testDB;