Olá PessoALL,
Hoje post pratico e rápido… e o título meio estranho ao ler… mas como removemos a hora, minuto e segundo de um campo de datatype DATETIME no SQL Server? Ou truncar as horas, como é dito por muitos profissionais Oracle?. Sabe aqueles momentos que você quer buscar todos os registros de um único dia mas ele possui hora, minuto e segundo?
Pois bem….. vamos a principio lembrar que existem N tipos de datatypes para se trabalhar com datas no SQL Server. Eles estão listados aqui neste link. Vamos lembrar também que o SQL Server não salva datas com formato, como já postei e exemplifiquei neste post.
Agora… a título de ilustração vamos imaginar a tabela abaixo.
create table table2 ( id_registro int primary key identity, horario_registro datetime not null, comentario varchar(512) not null );
Imagine que nesta tabela possui diversos registros por dia (horario_registro) e você quer apenas os de hoje. Quais são as opções?
Talvez essa?
select * from table2 where horario_registro = '20160622'
A consulta acima não irá trazer nenhum registro, por que? Claro…. você está passando o dia que será realizado “casting” dele para o DATETIME, que terá as “horas zeradas”, ou seja meia-noite, e nenhum registro foi inserido nesse horário. Como eu sei que foi “castado” para datetime? Veja o plano de execução.
Pois bem…. então vamos remover as horas do “horario_registro” ou melhor dizendo realizar “casting” dele para DATE.
select * from table2 where cast(horario_registro as date) = '20160622'
Agora sim ….. temos o resultado que queríamos… certo?
A solução vai funcionar muito bem para pequenas tabelas e validações rápidas.
Como ela funciona? O campo “horario_registro” será convertido para o tipo DATE, este não armazena hora, minuto e segundo. Assim o SQL Server não usará esses atributos durante o comparativo. O SQL Server é inteligente e fará também o casting do valor a ser pesquisado para DATE, diferente da ultima tentativa que foi feito casting para DATETIME.
Vejamos no plano de execução….
Pois bem… então o “zerar as horas” ou “truncar as horas” é simplesmente o casting do campo/valor de DATETIME para DATE? Exatamente!
Agora… esse método é o recomendado? Não! Por que não? Porque ele irá atrapalhar o SQL Server de usar índices! Então como podemos procurar um dia inteiro em um campo de DATETIME?
-- Usando menor ( < ) select * from table2 where horario_registro >= '20160622 00:00:00' and horario_registro < '20160623 00:00:00'
ou…
-- Usando menor igual ( <= ) select * from table2 where horario_registro >= '20160622 00:00:00' and horario_registro <= '20160622 23:59:59.997' <pre>
Ou usando variáveis…
declare @hoje_inicio datetime = cast(getdate() as date) declare @hoje_final datetime = dateadd(day, 1, @hoje_inicio) -- Usando menor ( < ) select * from table2 where horario_registro >= @hoje_inicio and horario_registro < @hoje_final
ou…
declare @hoje_inicio datetime = cast(getdate() as date) declare @hoje_final datetime = dateadd(day, 1, @hoje_inicio) -- Usando menor igual ( <= ) set @hoje_final = dateadd(MILLISECOND, -3, dateadd(day, 1, @hoje_inicio) ) select * from table2 where horario_registro >= @hoje_inicio and horario_registro <= @hoje_final
Explicando…
Por que a variável é DATETIME e foi atribuido o getdate() com CAST as DATE? Para truncar as horas! A variável terá o valor do dia de hoje com as como “00:00:00.000”!
Por que “20160622 23:59:59.997” e “dateadd(MILLISECOND, -3”? Porque o tipo DATETIME possui a precisão de até três casas após segundos, ou em milissegundos. Isso muda conforme muda o tipo para smalldatetime, timestamp, datetime2 e etc.
Em resumo…. pratico e rápido? Principalmente usando em variáveis? CAST as DATE!
Por hoje é só… vou corrigindo e aprimorando com o tempo…. vlw!