从 VARCHAR 列创建新 DateTime 列的最佳方法

Best way to create new DateTime column from VARCHAR column

我有一个 table,有 1M 行和一个 CREATED_AT varchar 列。此列中日期字符串的格式:

我想将此字符串转换为新的 datetime 列(称为 CREATED_DT)。

尝试次数

select 
    cast([CREATED_AT] as datetime) 
from
    [mydb].[dbo].[mytable]

错误:

Conversion failed when converting date and/or time from character string

select 
    convert(datetime, [CREATED_AT]) 
from 
    [mydb].[dbo].[mytable]

Conversion failed when converting date and/or time from character string

select 
    try_convert(DateTime, [CREATED_AT]) 
from
    [mydb].[dbo].[mytable]

查询已执行,但 returns 所有空值。

select 
    try_convert(DateTime, [CREATED_AT], 108) 
from
    [mydb].[dbo].[mytable]

查询已执行,但 returns 所有空值。

select 
    try_cast([CREATED_AT] as datetime) 
from
    [mydb].[dbo].[mytable]

查询已执行,但 returns 所有空值。

假设你永远不必关心最后无用的 +00(它总是 +00 或者你不在乎它是否是其他东西),你输了也没关系稍微精确一点,您可以取左边的 22 个字符并尝试使用安全样式编号(在您的情况下为 120)转换这些值:

DECLARE @d table(CREATED_AT varchar(32));

INSERT @d(CREATED_AT) VALUES
('2021-10-13 05:03:42.638+00'),
('2021-10-18 21:28:49.98+00'),
('2021-12-08 02:09:03.17+00');

SELECT CREATED_AT, 
  as_datetime = TRY_CONVERT(datetime, LEFT(CREATED_AT, 22), 120) 
FROM @d;

如果您不想丢失精度(例如,您不能将 .638 保留为 datetime,无论如何),或者某些值可能有 1 位或 0 位小数,或者某些值可能根本不包含 +xx,您可以做类似的事情,但使用一些字符串技巧来截断 + 出现的值(如果不出现,也会处理):

SELECT CREATED_AT,
  as_datetime2 = TRY_CONVERT(datetime2(3), 
    LEFT(CREATED_AT, COALESCE(NULLIF(CHARINDEX('+', 
    CREATED_AT), 0), 32)-1), 120) 
FROM @d;

要说明为什么在此处使用 120 样式编号很重要,请参阅 this db<>fiddle

您正在寻找的样式是 127,但您的问题是您只包括时区的小时,您还需要分钟。所以只需将 :00 添加到每个值即可。

然后您可以使用 SWITCHOFFSET

从那里转换为常规 datetime
DECLARE @v varchar(30) = '2021-10-13 05:03:42.638+00';

SELECT TRY_CONVERT(datetimeoffset, @v + ':00', 127);

SELECT CONVERT(datetime, SWITCHOFFSET(TRY_CONVERT(datetimeoffset, @v + ':00', 127), 0));

db<>fiddle