从字符串插入日期:CAST 与 CONVERT

pmd*_*dci 7 sql-server t-sql type-conversion azure-sql-database cast

考虑以下两种将日期时间 varchar 字符串转换为日期字段的方法:

SELECT convert(date, '2012-12-21 21:12:00', 20) -- Only date is needed
SELECT cast('2012-12-21 21:12:00' as date) -- Only date is needed
Run Code Online (Sandbox Code Playgroud)

两者都返回我期望的内容:不包括时间的日期,作为日期数据类型。

我的问题是:这两种方式有什么利弊吗?

Sol*_*zky 11

(以前)接受的答案 是不正确的 是一个糟糕的和误导性的测试。由于一个简单的错字导致它们不是苹果对苹果的比较,因此被比较的两个查询不会做同样的事情。接受答案中的测试不公平地偏向于CAST操作。问题是CONVERT操作正在使用convert(date, GETDATE()+num,20)- 一个值来转换每行的变化 - 而CAST操作正在使用一个简单的cast(GETDATE() as date)- 一个值来完成,该值在所有行中一致并在执行计划中被替换作为常数。事实上,查看 XML 执行计划甚至显示实际执行的操作是CONVERT(date,getdate(),0)!!

就我的测试显示(通过 using 使它们相等之后cast(GETDATE()+num as date)),时间因它们几乎相同(如果它们都被减少到CONVERT无论如何是有意义的)或CONVERT获胜而变化:

SET STATISTICS IO, TIME ON;
    ;with t as (
               select convert(date, GETDATE(),20) as fecha , 0 as num
             union all
             select convert(date, GETDATE()+num,20) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

-- 4754-07-23
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 9031 ms,  elapsed time = 9377 ms.



-- VS    

SET STATISTICS IO, TIME ON;
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE() as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

--2016-08-26
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 8969 ms,  elapsed time = 9302 ms.




SET STATISTICS IO, TIME ON;
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE()+num as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

-- 4754-07-23
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 9438 ms,  elapsed time = 9878 ms.
Run Code Online (Sandbox Code Playgroud)

之间的主要区别CAST和CONVERTCONVERT允许的“风格”来指定。“样式”不仅允许在将非字符串转换为字符串时定制输出,还允许在将字符串转换为非字符串时指定输入格式:

SELECT CONVERT(DATE, '5/10/2016', 101); -- 101 = mm/dd/yyyy
-- 2016-05-10


SELECT CONVERT(DATE, '5/10/2016', 103); -- 103 = dd/mm/yyyy
-- 2016-10-05
Run Code Online (Sandbox Code Playgroud)

现在将其与功能进行比较CAST

SELECT CAST('13/5/2016' AS DATE);
-- Msg 241, Level 16, State 1, Line 71
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 101); -- 101 = mm/dd/yyyy
-- Msg 241, Level 16, State 1, Line 76
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 103); -- 103 = dd/mm/yyyy
-- 2016-05-13
Run Code Online (Sandbox Code Playgroud)

还要提及的另一件事是CAST:因为它没有“样式”参数,所以传入的日期字符串的格式被假定为当前文化(会话属性)的格式。当前文化由系统变量@@LANGID@@LANGUAGE系统变量表示。这意味着CAST直接在上面的测试中失败的语句对于不同的文化/语言可能会成功。以下测试显示了这种行为以及CAST当当前语言为“法语”时相同的日期字符串如何工作(并且可以与其他几种语言一起使用,基于 中dateformat列中的值sys.syslanguages):

SELECT CAST('13/5/2016' AS DATE);
-- Msg 241, Level 16, State 1, Line 71
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 101); -- 101 = mm/dd/yyyy
-- Msg 241, Level 16, State 1, Line 76
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 103); -- 103 = dd/mm/yyyy
-- 2016-05-13
Run Code Online (Sandbox Code Playgroud)