функция для получения ввода символов и формата даты возврата (при неправильном вводе)

9

Мне нужно написать функцию, чтобы получить символ строки и вернуть формат даты. Например, ввод 20120101 и мне нужно это 2012-01-01. Проблема в том, что могут быть некоторые неверные данные, такие как «2012ABCD». В этом случае я хочу, чтобы функция возвращала фиксированную дату, такую ​​как 2020-01-01. То, что я написал до сих пор:

Create Function ReturnDate
(@date varchar(8))

Returns date

  as

    begin
       declare @result date

          set @result = (select convert(date , @date,111))
                if(@@ROWCOUNT>0) return @result
                 else return '2020-01-01'
       return @result
    end

Это не работает, и я просто не знаю, как обрабатывать вторую часть (когда ввод неправильный).

Пантеа Туранг
источник
1
Я мог бы порекомендовать вам прочитать «Запрос данных с помощью Transact-SQL». Если вы будете много заниматься программированием на SQL, эта книга научит вас основам программирования таких вещей. amazon.com/Exam-70-761-Querying-Data-Transact-SQL-ebook/dp/…
Тони Хинкль
1
Вы хотите строгий разбор для yyyymmddформата?
Дан Гузман

Ответы:

9

В SQL Server 2012 и более поздних версиях вы можете использовать TRY_CONVERT, чтобы проверить, можно ли преобразовать входные данные. Если это невозможно, возвращается значение NULL, поэтому вы можете выполнить COALESCE, чтобы получить либо преобразованное значение, либо фиксированную дату.

begin
   declare @result date
   set @result = COALESCE(TRY_CONVERT(date, @date, 111), '2012-01-01')
   return @result
end

Вы также можете использовать TRY CATCHблок и вернуть фиксированную дату в CATCHблоке, но рекомендуется использовать TRY_CONVERT, чтобы SQL Server не обрабатывал ошибку, поскольку это требует больше времени и ресурсов.

Функция для этого типа кода будет сопряжена с большими издержками, чем просто использование одной и той же логики в запросе, поэтому, если она вызывается много раз каждую секунду, вы можете потратить значительный ресурс, используя для него функцию. Я понимаю, что это может быть вызвано из множества кусков кода, поэтому есть желание сделать его функцией в случае, если нужно изменить дату по умолчанию - тогда скомпилированный код не изменится, а просто обновите эту функцию.

Если этот код будет выполняться много, вы должны рассмотреть другие варианты, которые обеспечат лучшую производительность, чем пользовательская функция. Пожалуйста, смотрите ответ Соломона для обзора ваших вариантов и дальнейшего объяснения того, почему вы можете выбрать один из других.

Например, ниже показана та же логика, реализованная в виде встроенной табличной функции, которую необходимо использовать, CROSS APPLYесли она не снабжена статическим значением, но работает намного лучше, чем скалярный UDF:

USE [tempdb];

GO
CREATE
OR ALTER -- comment out if using pre-SQL Server 2016 SP1
FUNCTION dbo.ReturnDate (@Date VARCHAR(8))
RETURNS TABLE
AS RETURN
  SELECT ISNULL(TRY_CONVERT(DATE, @Date, 111), '2020-01-01') AS [TheDate];
GO


SELECT *
FROM   (VALUES (1, '20120101'), (2, '2012ABCD')) tab(ID, Input)
CROSS APPLY dbo.ReturnDate(tab.[Input]) dt
/*
ID    Input       TheDate
1     20120101    2012-01-01
2     2012ABCD    2020-01-01
*/
Тони Хинкль
источник
6
Но я бы просто использовал TRY_CONVERT в запросе и отбросил бы всю идею использования неэффективного скалярного UDF для этого ...
Аарон Бертран
2
Меня не особо интересуют точки повторения, поэтому я не говорю об этом из-за их потери, но сообщество не выиграет от понижения явно правильного ответа. Вместо того, чтобы понизить голосование, напишите ответ, отредактируйте мой или оставьте комментарий о том, что нужно изменить. ОП запросил функцию, и я понимаю, что это может быть не лучшим решением, но это решение, которое было запрошено.
Тони Хинкль
3
Тони: Я не голосовал против, но я, безусловно, согласен с тем, что кто-то не должен голосовать против, не предоставив аргументацию в комментарии или не проголосовав за существующий комментарий, который включает их аргументацию. Тем не менее: 1)FINALLY в T-SQL нет блока (думаю, вы имели в виду CATCH). 2) Вы, вероятно, должны упомянуть, что TRY_CONVERTначалось в 2012 году (некоторые люди застряли до SQL Server 2012). 3) вы рассматривали Inline TVF? У них нет таких проблем с производительностью, как у скалярных UDF.
Соломон Руцкий
1
@TonyHinkle Спасибо за внесение этих изменений и за ссылку на мой SO ответ :). Тем не менее, я не уверен, сколько читателей смогут сделать скачок от просмотра логики UDF и чтения, что встроенный TVF будет лучше, до успешной реализации iTVF. Итак, я пошел дальше и добавил его в конец вашего ответа.
Соломон Руцкий
1
@SolomonRutzky Спасибо. Я на самом деле не разработчик SQL, так что это все еще над моей головой. Может быть, я не должен отвечать на что-то подобное, но это огромная возможность для обучения.
Тони Хинкль