Armazenar os dados em uma única coluna é a maneira preferida, pois eles estão inextricavelmente vinculados. Um ponto no tempo é uma única informação, não duas.
Uma maneira comum de armazenar dados de data / hora, empregados "nos bastidores" por muitos produtos, é convertendo-os em um valor decimal em que a "data" é a parte inteira do valor decimal e a "hora" é o fracionário valor. Portanto, 1900-01-01 00:00:00 é armazenado como 0.0 e 20 de setembro de 2016 9:34:00 é armazenado como 42631.39861. 42631 é o número de dias desde 1900-01-01. .39861 é a parte do tempo decorrido desde a meia-noite. Não use um tipo decimal diretamente para fazer isso, use um tipo explícito de data / hora; meu ponto aqui é apenas uma ilustração.
Armazenar os dados em duas colunas separadas significa que você precisará combinar os dois valores da coluna sempre que quiser ver se um determinado momento é anterior ou posterior ao valor armazenado.
Se você armazenar os valores separadamente, invariavelmente encontrará "bugs" difíceis de detectar. Tome, por exemplo, o seguinte:
IF OBJECT_ID('tempdb..#DT') IS NOT NULL
DROP TABLE #DT;
CREATE TABLE #DT
(
dt_value DATETIME NOT NULL
, d_value DATE NOT NULL
, t_value TIME(0) NOT NULL
);
DECLARE @d DATETIME = '2016-09-20 09:34:00';
INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);
SET @d = '2016-09-20 11:34:00';
INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);
/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.dt_value >= '2016-07-01 11:00:00';
/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.d_value >= CONVERT(DATE, '2016-07-01')
AND dt.t_value >= CONVERT(TIME(0), '11:00:00');
No código acima, estamos criando uma tabela de teste, preenchendo-a com dois valores e, em seguida, realizando uma consulta simples nesses dados. O primeiro SELECT
retorna as duas linhas; no entanto, o segundo SELECT
retorna apenas uma única linha, que pode não ser o resultado desejado:
A maneira correta de filtrar um intervalo de data / hora em que os valores estão em colunas discretas, conforme apontado por @ypercube nos comentários, é:
WHERE dt.d_value > CONVERT(DATE, '2016-07-01') /* note there is no time component here */
OR (
dt.d_value = CONVERT(DATE, '2016-07-01')
AND dt.t_value >= CONVERT(TIME(0), '11:00:00')
)
Se você precisar separar o componente de tempo para fins de análise , considere adicionar uma coluna calculada e persistente para a parte de tempo do valor:
ALTER TABLE #DT
ADD dt_value_time AS CONVERT(TIME(0), dt_value) PERSISTED;
SELECT *
FROM #dt;
A coluna persistida pode então ser indexada, permitindo classificações rápidas, etc., por hora do dia.
Se você estiver pensando em dividir a data e a hora em dois campos para fins de exibição, deve perceber que a formatação deve ser feita no cliente, não no servidor.