从 VARCHAR 列创建新 DateTime 列的最佳方法
Best way to create new DateTime column from VARCHAR column
我有一个 table,有 1M 行和一个 CREATED_AT varchar
列。此列中日期字符串的格式:
- 2021-10-13 05:03:42.638+00
- 2021-10-18 21:28:49.98+00
- 2021-12-08 02:09:03.17+00
我想将此字符串转换为新的 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));
我有一个 table,有 1M 行和一个 CREATED_AT varchar
列。此列中日期字符串的格式:
- 2021-10-13 05:03:42.638+00
- 2021-10-18 21:28:49.98+00
- 2021-12-08 02:09:03.17+00
我想将此字符串转换为新的 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));