Ошибка преобразования строки ISO в datetime

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я пытаюсь преобразовать varchar(255) в datetime в SQL. Я нашел этот пример:

 DECLARE @IsoDate nvarchar(255)
SET @IsoDate = '2010-03-16T19:20:30.45123 01:00'

-- CONVERT TO DATETIME in SQL 2008
SELECT CAST(CONVERT(datetimeoffset, @IsoDate) AS datetime) as SQL2008

 

и это работает отлично. Поскольку я хочу изменить формат столбца для целого столбца, я попытался

 SELECT CAST(CONVERT(datetimeoffset, [col1]) AS datetime) 
from [table]
 

но это выдает ошибку: ошибка преобразования при преобразовании даты и / или времени из символьной строки.
Я не понимаю, в чем проблема, единственный способ, которым он работал с использованием столбца, — это

 SELECT CAST(Left([col1]),18) AS datetime) 
from [table]
 

но я бы предпочел не обрезать строку.

Ответ №1:

Вы можете использовать

 SELECT *
from [table]
WHERE TRY_CONVERT(datetimeoffset, [col1]) IS NULL
 

чтобы увидеть, какие значения вызывают проблемы.

Если ваша версия (поскольку у вас есть комментарий к SQL Server 2008) не поддерживается TRY_CONVERT , и TRY_CAST вы можете выбрать часть записей, чтобы найти проблемы, используя предложение loop / where.

Ответ №2:

но я бы предпочел не обрезать строку.

Почему? При преобразовании DateTimeOffset в DateTime информация о часовом поясе в любом случае усекается (см. Документацию), и поскольку вы заявили, что это решает вашу проблему, это означает, что единственные места, где содержимое вашей строки вызывает проблемы, находятся где-то в этой части строки.

Кроме того, поскольку ваша строка ISO8601, вы можете безопасно использовать cast вместо convert (какой смысл использовать convert , если вы все равно не собираетесь использовать style параметр?) — или, что еще лучше, используйте try_cast (если вы не работаете с версией ниже 2012, которую в этом случае вам следует рассмотреть возможность обновления, поскольку это самая старая версия, которая все еще поддерживается) — так:

 SELECT CAST(TRY_CAST([col1] AS datetimeoffset) AS datetime2(7))
FROM [table]
 

При этом было бы лучше хранить значения datetime с учетом часового пояса DateTimeOffset в типе данных — и другие значения datetime в DateTime2 типе данных (что лучше, чем DateTime во всех отношениях).

Ответ №3:

Ваш код не работает, потому что у вас неверные значения. Вы можете игнорировать их, используя try_convert() :

 SELECT CAST(TRY_CONVERT(datetimeoffset, [col1]) AS datetime) 
FROM [table]
 

Это поддерживается во всех поддерживаемых версиях SQL Server.

Поскольку часовой пояс игнорируется в этом процессе, вы также можете просто использовать:

 select try_convert(datetime, left(col1, 23))