Primeiro de tudo, você não pode ficar sem eles, certo?
Conversões de dados SQL ou, mais especificamente, conversões de tipos de dados são uma parte essencial do trabalho de programação regular de um desenvolvedor de banco de dados ou DBA.
Agora, e se seu chefe assinasse um contrato com outra empresa para fornecer a eles um arquivo em formato de texto proveniente de seu banco de dados SQL Server?
Isso soa como um desafio emocionante!
Mas você descobriu que teria que lidar com uma data em uma string, um número em uma string e várias outras conversões de dados SQL. Você ainda está pronto para o desafio?
Não sem seu arsenal de truques de conversão de dados!
O que está disponível pronto para uso?
Quando comecei a programar T-SQL, a primeira coisa que vi que se encaixava no propósito da conversão foi o CONVERT () função.
Além disso, a palavra “converter” está lá, certo?
Embora isso possa ser verdade, é apenas uma das 4 maneiras de realizar esse trabalho. E eu estava usando para quase TODA a minha conversão de dados SQL. Estou feliz por ter superado isso. Porque eu aprendi que os 4 métodos têm seu próprio lugar no seu código.
Antes de chegarmos ao assunto do post, deixe-me apresentar os 4 métodos prontos para realizar a conversão de dados SQL:
- ELENCO ()
- CONVERTER ()
- PARSE ()
- TRY_CAST (), TRY_CONVERT (), TRY_PARSE ()
Cada uma das seções abaixo irá:
- Explique o que é
- Dizer quando usá-lo (casos de uso)
- Apresente suas limitações
- Dê exemplos e explique-os
Tudo apresentado neste artigo está em inglês claro e simples, tanto quanto possível. Ao terminar de ler o post inteiro, você saberá qual método é apropriado para uma determinada situação.
Então, sem mais delongas, vamos mergulhar.
1. Conversão de dados SQL usando CAST()
Embora todos os métodos que você verá possam converter tipos de dados, sua primeira escolha na conversão deve definitivamente ser CAST ().
Aqui estão as razões do porquê:
- É a função de conversão mais rápida de todas. Tentaremos provar isso mais adiante neste post.
- Está incluído nos padrões de especificação da linguagem SQL-92. Portanto, quando você precisar portar seu código para outros produtos SQL, como MySQL, a função também estará disponível.
Aqui está uma sintaxe muito simples para CAST ():
CAST( <expression> AS <data_type>[(length)] )
Primeiro, vamos examinar a sintaxe:
- <expressão> é qualquer expressão válida que resulta em um valor que pode ser convertido no tipo de dados de destino.
- <tipo_dados> é o tipo de dados de destino.
- comprimento é opcional e diz respeito ao tamanho dos dados.
Quando usar
Se a única coisa que você precisa é converter um valor para outro tipo de dados, então CAST () é exatamente o que você precisa.
Limitação
Do lado negativo, CAST () não pode fornecer uma saída formatada pronta para uso, como um valor de data e hora formatado.
Exemplos
A. Converter uma string em uma data:
SELECT CAST('09/11/2004 4:30PM' as datetime2)
E executar a instrução acima resultará em:
B. Converter um número em uma string:
SELECT CAST(10.003458802 as varchar(max))
E o resultado da conversão acima é:
Agora, se você precisar de algo mais como formatar os dados convertidos, o próximo método pode ajudá-lo.
2. Conversão de dados SQL usando CONVERT()
A próxima opção de conversão de dados é usar CONVERT (). Como eu disse antes, este é o que eu mais usei nos primeiros dias.
Aqui está a sintaxe:
CONVERT( <data_type>[(length)], <expression> [, <style>])
Da sintaxe acima, observe que o <estilo> parâmetro é opcional. E, a menos que você a forneça, a função será semelhante a CAST ().
Foi aí que minha confusão começou quando eu era novo no SQL.
Quando usar
Se você converter os dados em um formato instantâneo, CONVERT () é seu amigo. O que significa que você trata o <estilo> parâmetro corretamente.
Limitações
- ELENCO () é mais rápido que CONVERT (), então se você só precisa converter os dados, use CAST (). Se a saída precisar ser formatada, use CONVERT ().
- CONVERTER () não é um padrão SQL-92, portanto, se você precisar portá-lo para outro RDBMS, evite usá-lo.
Exemplos
A. Converter uma data em um formato de string aaaammdd
No exemplo a seguir, usarei o banco de dados de amostra AdventureWorks e transforme a [DataDeInício ] coluna para aaaammdd :
USE AdventureWorks
GO
SELECT
[BillOfMaterialsID]
,CONVERT(varchar(10), [StartDate],112) as StartDate
FROM [Production].BillOfMaterials]
GO
Observe que o estilo 112 é usado para formatar datas para aaaammdd .
B. Converta um número em uma string com vírgulas a cada 3 dígitos à esquerda do ponto decimal.
Da mesma forma, o exemplo a seguir ilustrará o AdventureWorks banco de dados de exemplo, e formataremos o número com vírgulas e com 2 casas decimais.
USE AdventureWorks
GO
SELECT
[TransactionID]
,[ProductID]
,CONVERT(varchar(10),[TransactionDate] ,112) as StartDate
,[Quantity]
,CONVERT(varchar(10),[ActualCost],1) as ActualCost
FROM [Production].TransactionHistory
GO
Observe que o formato 1 é usado para [Custo Real ]. E graças a CONVERT (), podemos formatar essas colunas em um instante.
No entanto, e se você precisar converter uma expressão de data mais longa? Irá CONVERTER () trabalhar nesse caso? Continue lendo para saber mais sobre o próximo método.
3. Conversão de dados SQL usando PARSE()
O próximo método que vamos considerar é PARSE ().
Confira a sintaxe:
PARSE( <string value> AS <datatype> [USING <culture>])
Quando usar
- Para converter strings em datas ou números usando uma cultura específica.
- Quando a string não pode ser convertida em uma data ou um número usando CAST () ou CONVERTER (). Veja os exemplos para obter mais informações.
Limitações
- A conversão só é possível para string em datas e string em números
- Conta com a presença do .Net Framework Common Language Runtime (CLR) no servidor.
- Não está incluído nas especificações padrão do SQL-92, portanto, a portabilidade para outro RDBMS é um problema.
- Tem sobrecarga de desempenho quando se trata de analisar a string.
Exemplos
A. Convertendo uma string de data longa
SELECT PARSE('Monday, June 8, 2020' as datetime USING 'en-US')
O exemplo acima é uma string de data longa a ser convertida em um datetime valor usando a cultura inglesa dos EUA. E é aqui que PARSE () fará o seu melhor.
Isso porque o código acima falhará se você usar CAST () ou CONVERTER ().
B. Convertendo um valor monetário com um símbolo de moeda
SELECT PARSE('€1024,01' as money using 'de-DE')
Agora, tente fazer a conversão usando CAST () e CONVERTER ()
SELECT CONVERT(money,'€1024,01')
SELECT CAST('€1024,01' as money)
A declaração não irá gerar erros, ainda assim, dê uma olhada neste resultado inesperado:
Como resultado, o valor foi convertido para 102401,00 em vez de 1024,01.
Até agora, descobrimos que os 3 primeiros métodos são propensos a erros, a menos que você os verifique. No entanto, o 4º método pode ser sua solução para o resultado defeituoso.
4. Conversão de dados SQL usando TRY_CAST(), TRY_CONVERT() ou TRY_PARSE()
Por fim, o último método para conversão de dados SQL é usar uma variante das 3 primeiras, mas com o prefixo TRY_.
Mas mesmo assim, qual é a diferença?
Eles têm os mesmos parâmetros que os 3 anteriores sem o prefixo TRY_. Mas a diferença é que eles retornam NULL se o valor não puder ser convertido. Agora, se o valor não puder ser convertido por nenhum dos 3 explicitamente, ocorrerá um erro. Veja os exemplos abaixo para entender melhor.
Quando usar
Você pode usar qualquer um dos 3 com instruções condicionais como CASE QUANDO ou IIF para testar os erros.
Limitações
Os 3 deles têm as mesmas limitações que os sem o prefixo TRY_, exceto para valores que não podem ser convertidos.
Exemplos
A. Use TRY_CAST() para testar se a conversão será bem-sucedida usando IIF:
SELECT IIF(TRY_CAST('111b' AS real) IS NULL, 'Cast failed', 'Cast succeeded') AS Result
O código acima retornará 'Falha na transmissão' porque '111b' não pode ser convertido para real . Retire o 'b' do valor e ele retornará 'Transmissão bem-sucedida'.
B. Usando TRY_CONVERT() em datas com um formato específico
SET DATEFORMAT dmy;
SELECT TRY_CONVERT(datetime2, '12/31/2010') AS Result
Isso retornará NULL porque o formato usa dmy ou dia-mês-ano. E a expressão de entrada para TRY_CONVERT () está no formato de mdy ou mês-dia-ano. O erro foi acionado porque o valor do mês é 31.
C. Usando TRY_PARSE() que irá gerar um erro de tempo de execução
SELECT
CASE WHEN TRY_PARSE('10/21/2133' AS smalldatetime USING 'en-US') IS NULL
THEN 'True'
ELSE 'False'
END AS Result
Este código irá gerar um erro de tempo de execução como visto abaixo:
É isso para os 4 métodos prontos para uso na conversão de dados SQL. Mas há mais por vir.
Que tal a conversão de dados SQL usando a conversão implícita?
Agora vamos considerar a conversão implícita. Este é um método silencioso.
Por que silencioso?
Porque você pode já estar fazendo isso, mas não tem consciência disso. Ou, pelo menos, você sabe que está acontecendo, mas está ignorando.
Em outras palavras, esse é o tipo de conversão que o SQL faz automaticamente sem nenhuma função.
Deixe-me lhe dar um exemplo:
DECLARE @char CHAR(25)
DECLARE @varchar VARCHAR(25)
DECLARE @nvarchar NVARCHAR(25)
DECLARE @nchar NCHAR(25)
SET @char = 'Live long and prosper'
SET @varchar = @char
SET @nvarchar = @varchar
SET @nchar = @nvarchar
SELECT @char AS [char], @varchar AS [varchar], @nvarchar AS [nvarchar], @nchar AS [nchar]
O código acima será executado com sucesso. Experimente você mesmo, e você terá um resultado semelhante ao abaixo:
Vamos tentar isso com datas:
DECLARE @datetime datetime
DECLARE @smalldatetime smalldatetime
DECLARE @datetime2 datetime2
SET @datetime = '12/31/2050 14:34'
SET @smalldatetime = @datetime
SET @datetime2 = @smalldatetime
SELECT @datetime as [datetime], @smalldatetime as [smalldatetime], @datetime2 as [datetime2]
Como esperado, isso produzirá um resultado bem-sucedido:
Vamos tentar desta vez com números:
DECLARE @int int
DECLARE @real real
DECLARE @decimal decimal
DECLARE @float float
SET @int = 1701
SET @real = @int
SET @decimal = @real
SET @float = @decimal
SELECT @int as [int], @real as [real], @decimal as [decimal], @float as [float]
Ainda um sucesso, certo?
Até agora, usamos valores simples que serão adequados para um tipo de dados bastante semelhante. Vamos entrar no próximo nível:números para strings.
DECLARE @number int
DECLARE @string varchar(5)
SET @number = 1701
SET @string = @number
SELECT @number as [number], @string as [string]
Isso será convertido com sucesso, como você pode ver no resultado abaixo:
Existem muitos outros casos em que o SQL Server tentará “adivinhar” como converter dados. Como você pode ver nesta referência, há muitas instâncias comparadas àquelas que requerem conversão explícita.
Como o SQL Server permite isso, isso significa que você pode permitir que isso aconteça livremente em todo o seu código?
Ressalvas na conversão implícita
Por um lado, pode ser conveniente. Mas assim que os limites de cada tipo de dados forem atingidos, você perceberá que a conversão implícita é um pouco perigosa se não for verificada.
Considere um exemplo abaixo:
DECLARE @char char(25)
DECLARE @varchar varchar(25)
DECLARE @nvarchar nvarchar(25)
DECLARE @nchar nchar(25)
SET @nvarchar = N'I ❤ U!'
SET @nchar = @nvarchar
SET @char = @nchar
SET @varchar = @nchar
SELECT @char as [char], @varchar as [varchar], @nvarchar as [nvarchar], @nchar as [nchar]
Você viu o valor do emoji? Isso contará como um valor unicode.
Embora todas as instruções acima sejam executadas com sucesso, as variáveis com tipos não-unicode como varchar e char terá resultados inesperados. Veja o resultado abaixo:
No entanto, esse não é o único problema. Os erros aparecerão quando o valor ficar fora do intervalo. Considere um exemplo com datas:
DECLARE @datetime datetime
DECLARE @smalldatetime smalldatetime
DECLARE @datetime2 datetime2
SET @datetime = '12/31/2374 14:34'
SET @smalldatetime = @datetime
SET @datetime2 = @smalldatetime
SELECT @datetime as [datetime], @smalldatetime as [smalldatetime], @datetime2 as [datetime2]
A atribuição do datetime valor para o smalldatetime variável irá acionar o erro como você pode ver abaixo:
Mas há outra ressalva, que você também deve estar ciente ao lidar com conversão implícita:sobrecarga de desempenho. Vendo que este é um tema quente, ele merece ter uma seção separada.
Implicações de desempenho de diferentes métodos de conversão de dados SQL
Acredite ou não, diferentes métodos de conversão de dados SQL terão desempenho diferente em situações reais. E você deve pelo menos estar ciente disso para evitar armadilhas de desempenho.
Como CAST(), CONVERT() e PARSE() funcionam
Primeiro, vamos examinar como CAST (), CONVERTER (), e PARSE () executar em condições naturais, comparando o que é mais rápido. Adaptamos e provamos o conceito do nosso exemplo retirado daqui. Considere o código abaixo:
USE AdventureWorks
GO
SET STATISTICS TIME ON
SELECT CAST([NationalIDNumber] as int) FROM [HumanResources].[Employee]
SELECT CONVERT(int,[NationalIDNumber]) FROM [HumanResources].[Employee]
SELECT PARSE([NationalIDNumber] as int) FROM [HumanResources].[Employee]
SET STATISTICS TIME OFF
GO
Agora, vamos examinar o código que usa o AdventureWorks banco de dados da Microsoft:
- DEFINIR TEMPO DAS ESTATÍSTICAS LIGADO gerará o tempo de CPU e o tempo decorrido em cada um dos SELECT declarações
- Então, a coluna que escolhemos converter para fins de demonstração é [NationalIDNumber ], que tem um tipo de nvarchar(15) .
- Além disso, a conversão é de uma string para um inteiro:nvarchar(15) para int .
- E por último, restauramos o SET STATISTICS TIME ao seu valor anterior
Observe a saída nas Mensagens guia do resultado da consulta:
Aqui está o que descobrimos usando este exemplo:
- Isso prova que CAST () executa o mais rápido (1 ms.) e PARSE () executa o mais lento (318 ms.).
- Seguimos essa precedência ao decidir qual função usar para converter dados:(1 ) ELENCO () (2 ) CONVERTER () (3 ) ANALISAR ().
- Lembre-se de quando cada função é relevante e considere as limitações ao decidir qual função usar.
Qual o desempenho da conversão implícita
Neste ponto, você deve ser capaz de ver que eu recomendo o uso de funções como CAST() para converter dados. E nesta seção, você verá o porquê.
Considere esta consulta usando os WideWorldImporters banco de dados da Microsoft. Antes de executá-lo, ative o Incluir Plano de Execução Real no SQL Server Management Studio .
USE WideWorldImporters
GO
SELECT
[CustomerID]
,[OrderID]
,[OrderDate]
,[ExpectedDeliveryDate]
FROM [Sales].[Orders]
WHERE [CustomerID] like '487%'
Na consulta acima, filtramos o resultado dos pedidos de venda com [CustomerID ] como '487%'. Isso é apenas para demonstrar que efeito a conversão implícita de um int tipo de dados tem em varchar .
Em seguida, examinamos o plano de execução abaixo:
Como você pode ver, há um aviso no SELECT ícone. Portanto, passe o mouse para ver a dica de ferramenta. Em seguida, observe a mensagem de aviso, ou seja, o CONVERT_IMPLICIT .
Antes de continuarmos, este CONVERT_IMPLICIT aviso ocorre quando é necessário realizar uma conversão implícita para SQL Server. Vejamos mais de perto o problema. Conforme descrito abaixo, o aviso tem 2 partes:
- CONVERT_IMPLICIT pode afetar "CardinalityEstimate" em uma escolha de plano de consulta.
- CONVERT_IMPLICIT pode afetar "SeekPlan" em uma escolha de plano de consulta.
Ambos indicam que sua consulta será executada mais lentamente. Mas sabemos o porquê, é claro. Forçamos intencionalmente uma conversão implícita usando um LIKE operador para um valor inteiro.
Qual é o ponto nisso?
- A conversão implícita de dados faz com que o SQL Server use CONVERT_IMPLICIT , o que retarda a execução da sua consulta.
- Para corrigir esse problema, elimine o uso de conversão implícita. No nosso caso, usamos [CustomerID ] Gostei '487%', podemos corrigi-lo alterando [CustomerID ] =487. A correção da consulta alterará o plano de execução da consulta, removerá o aviso anterior e alterará o operador de varredura de índice para uma busca de índice. No final, o desempenho melhora.
Final feliz? Sim!
Recomendações
Como mostrado, não podemos simplesmente deixar o SQL Server fazer a conversão com uma conversão implícita. Eu recomendo que você siga a precedência quando se trata de decidir o que usar ao converter dados.
- Primeiro, se você só precisa converter como está, use CAST (). É uma função mais padronizada quando se trata de portar para outros RDBMs.
- Em segundo lugar, se você precisar de dados formatados, use CONVERT ().
- Em terceiro lugar, se ambos CAST () e CONVERTER () falha ao fazer o trabalho, use PARSE ().
- Por último, para testar erros ao converter, use TRY_CAST (), TRY_CONVERT (), ou TRY_PARSE ().
Bem isso é tudo por agora. Espero que isso ajude você em suas próximas aventuras de codificação. Quebrar a perna!
Para saber mais sobre o tópico de conversão de dados SQL da Microsoft:
- CAST e CONVERT
- PARAR
- TRY_CAST, TRY_CONVERT e TRY_PARSE