Dados os seguintes componentes
DECLARE @D DATE = '2013-10-13'
DECLARE @T TIME(7) = '23:59:59.9999999'
Qual a melhor forma de combiná-los para produzir um DATETIME2(7)
resultado com valor '2013-10-13 23:59:59.9999999'
?
Algumas coisas que não funcionam estão listadas abaixo.
SELECT @D + @T
A data do tipo de dados do operando é inválida para o operador add.
SELECT CAST(@D AS DATETIME2(7)) + @T
O tipo de dados do operando datetime2 é inválido para o operador add.
SELECT DATEADD(NANOSECOND,DATEDIFF(NANOSECOND,CAST('00:00:00.0000000' AS TIME),@T),@D)
A função dateiff resultou em um estouro. O número de partes de data que separam duas instâncias de data/hora é muito grande. Tente usar datediff com um datepart menos preciso.
* O estouro pode ser evitado no Banco de Dados SQL do Azure e no SQL Server 2016, usando DATEDIFF_BIG
.
SELECT CAST(@D AS DATETIME) + @T
Os tipos de dados datetime e time são incompatíveis no operador add.
SELECT CAST(@D AS DATETIME) + CAST(@T AS DATETIME)
Retorna um resultado, mas perde a precisão
2013-10-13 23:59:59.997
Isso parece funcionar e manter a precisão também:
O
CAST
toDATETIME2(7)
converte oTIME(7)
valor (@T
) para umDATETIME2
onde a parte da data é'1900-01-01'
, que é o valor padrão dos tipos date e datetime (consultedatetime2
e o comentário * emCAST
eCONVERT
página no MSDN.)* ... Quando dados de caracteres que representam apenas componentes de data ou apenas de hora são convertidos para os tipos de dados datetime ou smalldatetime, o componente de hora não especificado é definido como 00:00:00.000 e o componente de data não especificado é definido como 1900-01- 01 .
A função
DATEADD()
eDATEDIFF()
cuida do resto, ou seja, somando a diferença em dias entre o1900-01-01
e oDATE
valor (@D
).Teste em: SQL-Fiddle
Conforme observado por @Quandary , a expressão acima é considerada não determinística pelo SQL Server. Se queremos uma expressão determinística, digamos porque ela deve ser usada para uma
PERSISTED
coluna, o'19000101'
** precisa ser substituído por0
ouCONVERT(DATE, '19000101', 112)
:**:
DATEDIFF(day, '19000101', d)
não é determinístico, pois faz uma conversão implícita da string paraDATETIME
e as conversões de strings para datetime são determinísticas somente quando estilos específicos são usados.Estou atrasado para a festa, mas essa abordagem, embora semelhante à resposta do @ypercube , evita a necessidade de usar qualquer conversão de string (que pode ser mais cara que as conversões de data), é determinística e deve continuar a funcionar se a MS alterar o valor de data padrão de 1900-01-01 (mesmo que eles provavelmente não mudem isso):
O princípio é que, convertendo o valor de hora para datetime2 e depois para date, ele retira o tempo limite e atribui a data padrão, você datediff isso com o valor de data para obter os dias a serem adicionados, lança seu tempo para datetime2 e adiciona o dias em.
Para SQL Server 2012 e superior, existe a função DATETIME2FROMPARTS . Tem esta forma:
Para os dados de amostra fornecidos, isso se torna
o que resulta em
As partes podem ser obtidas usando DATEPART() se partir de tipos de dados temporais, ou do texto usado para construir os valores de amostra na pergunta.
Eu estava procurando outra coisa quando cheguei aqui. A pergunta é bem antiga, mas há alguns comentários e atividades recentes. Pensei em compartilhar um método simples que é muito semelhante à resposta que @Atario deu, mas um pouco mais curto e alguns podem achar mais fácil de ler:
Converti os dois valores (@D e @T) para binário, concatenei valores binários e depois outra conversão de volta para DT2(7):
Resultados:
Ou, de forma mais compacta:
O
time(7)
valor é convertido embinary(6)
vez do tamanho de armazenamento documentado de 5 bytes porque, ao converter para binário, o SQL Server prefixa um byte de precisão para garantir que a conversão de ida e volta seja possível. Isso está documentado em uma nota de rodapé paradatetime2
mas nãotime
.A concatenação simples funciona neste caso porque a
time
precisão é a mesma que adatetime2
precisão desejada. Caso contrário, você precisaria remover o byte de precisão e substituí-lo pelo valor necessário.Esse método depende de detalhes de implementação que podem ser alterados e, portanto, não é documentado e não tem suporte .
db<>violino
É muito estúpido do SQL Server não deixar seu primeiro exemplo funcionar, e isso vai parecer muito idiota também, mas…