função para receber uma entrada de caracteres e formato de data de retorno (com entrada incorreta)

9

Preciso escrever uma função para receber um caractere de string e retornar o formato da data. Por exemplo, a entrada é 20120101 e eu preciso deste 01-01-2012. O problema é que pode haver algumas entradas incorretas como esta "2012ABCD". Nesse caso, desejo que a função retorne uma data fixa, como 01-01 2020. O que eu escrevi até agora é:

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

Isso não funciona e eu simplesmente não sei como lidar com a segunda parte (quando a entrada está incorreta).

Pantea Tourang
fonte
11
Eu recomendo que você leia "Consultando dados com o Transact-SQL". Se você estiver fazendo muita programação em SQL, este livro ensinará o básico de como codificar coisas como essa. amazon.com/Exam-70-761-Querying-Data-Transact-SQL-ebook/dp/…
Tony Hinkle
11
Deseja uma análise rigorosa do yyyymmddformato?
Dan Guzman

Respostas:

9

No SQL Server 2012 e posterior, você pode usar TRY_CONVERT para verificar se a entrada pode ser convertida. Se não puder, um valor NULL será retornado; portanto, você poderá executar um COALESCE para obter o valor convertido ou a data fixa.

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

Você também pode usar um TRY CATCHbloco e retornar a data fixa no CATCHbloco, mas é uma prática recomendada usar TRY_CONVERT para que o SQL Server não precise manipular um erro, pois isso requer mais tempo e recursos.

Uma função para esse tipo de código acarretará mais sobrecarga do que simplesmente usar a mesma lógica na consulta; portanto, se ela for chamada muitas vezes a cada segundo, você poderá consumir recursos significativos usando uma função para ela. Eu entendo que isso pode ser chamado a partir de vários trechos de código, portanto, há um desejo de torná-lo uma função, caso a data padrão precise ser alterada - então não há alterações no código compilado e atualize essa função.

Se esse código for executado muito, considere outras opções que fornecerão melhor desempenho do que uma função definida pelo usuário. Consulte a resposta de Salomão para obter uma visão geral de suas opções e mais explicações sobre por que você pode escolher uma sobre a outra.

Por exemplo, o seguinte mostra a mesma lógica implementada como uma função com valor de tabela embutida, que precisa ser usada CROSS APPLYse não for fornecida com um valor estático, mas que tem um desempenho muito melhor que uma UDF escalar:

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
*/
Tony Hinkle
fonte
6
Mas eu iria usar apenas TRY_CONVERT na consulta e descartar a idéia de usar um UDF escalar ineficiente para isso ...
Aaron Bertrand
2
Eu realmente não me importo com os pontos de representação, por isso não estou dizendo isso devido à perda de tais, mas a comunidade não se beneficia com o voto negativo de uma resposta obviamente correta. Em vez de reduzir a votação, escreva uma resposta, edite a minha ou deixe um comentário sobre o que precisa ser alterado. O OP pediu uma função e sei que talvez não seja a melhor solução, mas é a solução que foi solicitada.
Tony Hinkle
3
Tony: Não votei de forma negativa, mas certamente concordo que alguém não deveria votar de maneira negativa, sem fornecer o raciocínio em um comentário ou votar um comentário existente que inclua seu raciocínio. Dito isto: 1) não há nenhum FINALLYbloco no T-SQL (acho que você quis dizer CATCH). 2) você provavelmente deve mencionar que TRY_CONVERTcomeçou em 2012 (algumas pessoas estão paralisadas antes do SQL Server 2012). 3) você considerou um TVF em linha? Esses não têm os mesmos problemas de desempenho que os UDFs escalares.
Solomon Rutzky
11
@TonyHinkle Obrigado por fazer essas edições e pela referência à minha resposta SO :). Ainda assim, não tenho certeza de quantos leitores poderão dar um salto ao ver a lógica da UDF e ler que uma TVF em linha será melhor para implementar com sucesso a iTVF. Então, fui em frente e adicionei ao final da sua resposta.
Solomon Rutzky
11
@SolomonRutzky Thanks. Eu não sou realmente um desenvolvedor de SQL, então isso ainda está acima da minha cabeça. Talvez eu não deva responder algo assim, mas é uma tremenda oportunidade de aprendizado.
Tony Hinkle