La memorizzazione dei dati in una singola colonna è il modo preferito, poiché sono indissolubilmente collegati. Un punto nel tempo è una singola informazione, non due.
Un modo comune di memorizzare i dati di data / ora, utilizzati "dietro le quinte" da molti prodotti, è convertirli in un valore decimale in cui la "data" è la parte intera del valore decimale e il "tempo" è il frazionario valore. Quindi, 1900-01-01 00:00:00 viene archiviato come 0,0 e il 20 settembre 2016 9:34:00 viene archiviato come 42631.39861. 42631 è il numero di giorni dal 1900-01-01. .39861 è la parte di tempo trascorsa dalla mezzanotte. Non utilizzare direttamente un tipo decimale per fare ciò, utilizzare un tipo di data / ora esplicito; il mio punto qui è solo un'illustrazione.
Memorizzare i dati in due colonne separate significa che dovrai combinare entrambi i valori di colonna ogni volta che vuoi vedere se un dato momento è precedente o successivo al valore memorizzato.
Se memorizzi i valori separatamente, invariabilmente ti imbatterai in "bug" che sono difficili da rilevare. Prendi ad esempio quanto segue:
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');
Nel codice sopra, stiamo creando una tabella di test, popolandola con due valori, quindi eseguendo una semplice query su tali dati. Il primo SELECT
restituisce entrambe le righe, tuttavia il secondo SELECT
restituisce solo una singola riga, che potrebbe non essere il risultato desiderato:
Il modo corretto di filtrare un intervallo di data / ora in cui i valori sono in colonne discrete, come sottolineato da @ypercube nei commenti, è:
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 è necessario separare il componente temporale ai fini dell'analisi , è possibile prendere in considerazione l'aggiunta di una colonna calcolata, persistente, per la parte temporale del valore:
ALTER TABLE #DT
ADD dt_value_time AS CONVERT(TIME(0), dt_value) PERSISTED;
SELECT *
FROM #dt;
La colonna persistente potrebbe quindi essere indicizzata consentendo ordinamenti veloci, ecc. Per ora del giorno.
Se stai pensando di dividere la data e l'ora in due campi per scopi di visualizzazione, dovresti capire che la formattazione dovrebbe essere fatta sul client, non sul server.