Преобразование строк в дату в SQL

#sql #sql-server #date #tsql #sql-server-2017

Вопрос:

Я использую SQL Server 2017. Я пытаюсь обработать строки из поля свободного формата и либо преобразовать их в дату в формате «дд/мм/гггг», либо, если они не в этом формате, просто отобразите текст дословно.

Мне это нужно в ПРЕДСТАВЛЕНИИ, поэтому я не могу использовать ЗАДАННЫЙ ЯЗЫК. Звучит просто при использовании Convert и IsDate , кажется, не работает.

Поэтому для приведенного ниже фрагмента кода (помните, что это будет в представлении) я хочу прочитать текст, и если строка преобразуется в дату (т. Е. находится в формате dd/mm/yyyy , затем запустите преобразование в дату, как мне нужно, в формате даты, чтобы Excel мог выбрать (через подключение базы данных SQL Server)), и если оно не преобразуется в дату, отобразите текст как есть.

 create table dateTest1 
( 
    idx int, 
    dateStringTest varchar(15) 
); 
  
insert into dateTest1 (idx, dateStringTest) 
values (1, '13/01/2021'), (2, 'no'); 
 
select 
    case 
        when isdate(convert(datetime, dateStringTest, 103)) = 1 
            then convert(datetime, dateStringTest, 103)
        else dateStringTest 
    end as dtres
from 
    dateTest1 
--where idx = 1 
 

Ошибка:

Msg 241, Уровень 16, Состояние 1, Строка 15
Сбой преобразования при преобразовании даты и/или времени из символьной строки.

Эта ошибка возникает при idx = 2. Idx = 1 работает нормально.

Любая помощь в этом будет весьма признательна. Заранее спасибо.

Комментарии:

1. Столбец не может быть одновременно типом даты-времени и типом varchar одновременно. Если это должен быть столбец даты и времени, вам может потребоваться 2 запроса. 1 для действительных дат и 1 для не-дат

2. SQL Server 2017. Все равно не везет. У меня есть все данные, поступающие в excel без каких-либо ошибок. Но в столбцах EXCEL даты отображаются в виде строк. Они должны отображаться как Дата. Даже если я изменю формат столбца в Excel, он не изменит формат строки

3. Используйте TRY_CONVERT — он вернет a NULL , если переданное значение (the varchar ) не может быть преобразовано в дату — вместо того, чтобы выдавать ошибку

Ответ №1:

Вам нужно привести полученную дату к a varchar . A case expression может возвращать только один тип данных, а порядок приоритета означает, что он все еще пытается преобразовать значения varchar в datetime

 select 
       case when isdate( dateStringTest) = 1 
       then Cast(convert(datetime, dateStringTest, 103) as varchar(10))
       else dateStringTest 
       end as dtres
from dateTest1 
 

Вы можете сжать в один оператор (применяется тот же порядок приоритета)

 select IsNull(Cast(Convert(datetime,Try_Cast(dateStringTest as date),103) as varchar(10)),dateStringTest)
from datetest1
 

Комментарии:

1. Спасибо за ваш быстрый ответ. Как и выше, к сожалению, TRY_CONVERT не распознается. Я использую SQL SERVER 2017.

2. @gfsadmin — Я не уверен, что вы имеете в виду, try_convert поддерживается в SQL Server 2017. Видите эту рабочую скрипку

3. для try_convert требуется совместимость с 2012 годом, а наша база данных была совместима с 2008 годом. В любом случае это не решало проблему. Пытаюсь обработать строки в формате дд/мм/гггг, но когда скрипт считывает такую дату, как 13/06/2021, он терпит неудачу. Я хочу, чтобы это был формат даты, а не текстовый формат, буду признателен за любую помощь. Заранее спасибо

Ответ №2:

Основываясь на используемом вами синтаксисе, я предполагаю, что вы используете SQL Server. Вы должны добавить соответствующий тег к своему вопросу.

Единственный способ сделать это в одной колонке-оставить ее в виде текста.

Ваше использование ISDATE() неверно. Если dateStringTest не является допустимой датой, CONVERT() на SQL Server возникнет ошибка типа:

Преобразование типа данных varchar в тип данных datetime привело к значению вне диапазона.

Вот почему вы получаете ошибку для idx=2

Вы говорите, что вам «нужно это в формате даты, чтобы Excel мог подобрать». То, как Excel интерпретирует это, вероятно, будет зависеть от ваших языковых настроек. Предполагая mm/dd/yyyy , что это допустимо в вашем регионе, Excel, вероятно, уже рассматривает это как дату. Но я предполагаю, что этого не происходит, поэтому mm/dd/yyyy это недопустимо для вашего региона. Для меня, если у меня есть эта таблица в SQL…

 create table dateTest1 (
    id int identity(1,1) not null,
    dateStringTest varchar(20)
)

insert dateTest1
values
  ('2020-01-01')
, ('2020-21-01')
, ('2020-01-21')
, ('1/1/2020')
, ('1/21/2020')
, ('21/1/2020')
, ('21/01/2020')
, ('other stuff')
 

…и запросите его из Excel, добавив столбцы с функциями DATEVALUE , DAY , WEEKDAY , и YEAR , я получу…

ID Datestringтестировать ЗНАЧЕНИЕ ДАТЫ день будний день год
1 2020-01-01 43831 1 4 2020
2 2020-21-01 #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ!
3 2020-01-21 43851 21 3 2020
4 1/1/2020 43831 1 4 2020
5 1/21/2020 43851 21 3 2020
6 21/1/2020 #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ!
7 21/01/2020 #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ!
8 другие вещи #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ! #ЦЕННОСТЬ!

Это, по-видимому, указывает на то, что Excel распознает некоторые значения как даты.

Что вам нужно сделать , так это попытаться преобразовать значение в datetime , а затем, если это не удастся, сообщить об исходном значении. В обоих случаях выведите строку.

Вам следует ознакомиться с документацией для CONVERT() .

Попробуйте это:

 select dateStringTest
, coalesce(cast(try_convert(datetime, dateStringTest, 103) as varchar(20)), dateStringTest) as dtres1
, coalesce(convert(varchar(20), try_convert(datetime, dateStringTest, 103), 103), dateStringTest) as dtres2
, coalesce(convert(varchar(20), try_convert(datetime, dateStringTest, 103), 101), dateStringTest) as dtres3
from dateTest1
 

Обновить

Если вы рассматриваете dd/mm/yyyy в качестве дат только значения, соответствующие шаблону (поэтому 17/01/2021 является датой, а 17/1/2021-нет), этот метод грубой силы будет работать с SQL Server 2008 (уровень совместимости 100):

(Обратите внимание, что я также обновил свой ввод выше.)

 ;
with a as (
    select id
    , dateStringTest
    , SUBSTRING(dateStringTest, 7, 4)   '-'   SUBSTRING(dateStringTest, 4, 2)   '-'   SUBSTRING(dateStringTest, 1, 2) as converteDate
    from dateTest1
)

select id
, cast(convert(datetime, dateStringTest, 103) as varchar(20)) as dtres
from a
where isdate(converteDate) = 1

union
select id
, dateStringTest as dtres
from a
where isdate(converteDate) = 0
 

Комментарии:

1. Спасибо за ваш быстрый ответ. К сожалению, TRY_CONVERT не распознается. Я использую SQL SERVER 2017.

2. TRY_CONVERT работает в SQL Server 2012 и выше, если используется уровень совместимости 110 или выше. Проверьте уровень совместимости: select name , compatibility_level from sys.databases

3. И вот диаграмма, показывающая, какие уровни совместимости доступны в каких версиях SQL Server: glennsqlperformance.com/2020/08/20/…

4. Спасибо, я изменил его на совместимость с 2012 годом, и try_convert был распознан. Однако это не решило проблему. когда я вставляю другие даты, совместимые с «мм/дд/гггг» (т. Е. первая часть даты находится в диапазоне от 1 до 12), тогда утверждение, похоже, работает. Но в Австралии наш формат-дд/мм/гггг, а даты, в которых дата больше 12, тогда терпят неудачу. Я не могу использовать ЗАДАННЫЙ ЯЗЫК в ПРЕДСТАВЛЕНИИ. Не уверен, как сообщить ПРЕДСТАВЛЕНИЮ, что строка находится в формате дд/мм/гггг, а не мм/дд/гггг. Спасибо

5. Похоже, что SQL Server использует ваш язык, а Excel-нет. Возможно, вам будет полезно прочитать документацию CONVERT() и потратить время на эксперименты с ней. Смотрите мой пересмотренный ответ.