Cuidado com conversão de dados no SQL Server
Leonel Fraga de Oliveira 03/08/2010 00:20

Hoje (02/08/2010) aconteceu um erro um pouco incomum em um dos sistemas que desenvolvi no serviço. Era uma comparação de duas datas em uma cláusula IF no SQL Server.

Para simplificar a coisa, você saberia me dizer o resultado das duas expressões SQL à seguir?

declare @data1 datetime;
set @data1 = cast('05/20/2010' as datetime);

--Query 1
if (CONVERT(VARCHAR(20),coalesce(DATEADD ( DAY ,1, @DATA1 ),'01-01-1900 00:00:00') ,103) <= convert(varchar(20),getdate(),103))
end
begin
	select 'true';
else
begin
	select 'false';
end;

--Query 2
if (coalesce(DATEADD ( DAY ,1, @DATA1 ),'01-01-1900 00:00:00') <= getdate())
begin
	select 'true';
end
else
begin
	select 'false';
end;

A única diferença entre as consultas é que na primeira fazemos o uso da função CONVERT para retornar apenas a componente de data de um tipo DateTime qualquer, enquanto na segunda comparamos com o tipo “bruto”.

Ao rodar a query, uma surpresinha nada agradável: elas retornam resultados diferentes! Mas pô, não é a mesma coisa, não fazem a comparação entre duas datas?

Bem, comparação entre duas datas, vírgula! Você notou o primeiro argumento na função CONVERT da primeira query? Convertemos as datas em Varchar. Então, na verdade, o que estamos comparando na primeira consulta são duas strings e não duas datas como na segunda query, onde trabalhamos com o tipo DateTime em sua forma “bruta”.

Quando comparamos duas strings com os operadores menor, maior, menor ou igual ou maior ou igual, o que estamos comparando é a ordem alfabética. Estamos usando o operador <= na consulta, então, se o primeiro argumento da comparação, em ordem alfabética for o primeiro em relação ao segundo, o resultado do IF cairá em “false”.

No momento dessa consulta, a função getdate() já com o CONVERT retorna ‘02/08/2010’. E a data-base da comparação é ‘20/05/2010’. E se fomos classificar isso em ordem alfabética, a string ‘02/08/2010’ vem primeiro, ou seja, ela é menor que a string ‘20/05/2010’.

Ou seja, completamente diferente se fomos classificar usando o tipo DateTime.

Esta POG do Convert funciona se utilizarmos os operadores de igualdade e diferença, pois nesse caso a comparação de strings cabe perfeitamente nessas condições.

Então #comofas para comparar usando o tipo DateTime porém só pegando a componente de data?

Para isso, peguei na net uma função (UDF) que faz isso. A mágica dela é retornar as datas passadas como argumento à meia-noite, assim a componente de hora será sempre igual. Veja:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create  function [dbo].[DateOnly](@DateTime DateTime)
returns datetime
as
    begin
		return dateadd(dd,0, datediff(dd,0,@DateTime))
    end
GO

Agora, veja como fica a nossa query usando a UDF para comparar só as datas:

if (dbo.DateOnly(coalesce(DATEADD ( DAY ,1, @DATA1 ),'01-01-1900 00:00:00')) <= dbo.DateOnly(getdate()))
begin
	select 'true';
end
else
begin
	select 'false';
end;

PS: Não se esqueça de colocar o owner da função quando for utilizá-la!

É, meus queridos! Essa POG não funcionou de forma adequada. Portanto, muito cuidado ao utilizar conversão de dados para string em suas consultas SQL!

Um abraço ;)

Leonel Fraga de Oliveira Leonel Fraga de Oliveira é formado em Processamento de Dados na Faculdade de Tecnologia de São Paulo (FATEC-SP - 2002) e anteriormente em Técnico em Eletrônica, pela ETE Professor Aprígio Gonzaga (lá em 1999).
Atualmente trabalha como Analista de Sistemas na Prefeitura Municipal de São Caetano do Sul - SP
Tem como hobbies DJing (também trabalha como DJ freelancer) e ciclismo, além da manutenção dos sites NeoMatrix Light e NeoMatrix Tech.
Gosta de música eletrônica, tecnologia, cinema (super fã de Jornada nas Estrelas), gastronomia e outras coisas mais.


Compartilhe nas redes sociais

   

Deixe seu comentário

comments powered by Disqus