Przechowywanie danych w jednej kolumnie jest preferowanym sposobem, ponieważ są one nierozerwalnie połączone. Punkt w czasie to jedna informacja, a nie dwie.
Powszechnym sposobem przechowywania danych daty / godziny, stosowanym „za kulisami” przez wiele produktów, jest konwersja ich na wartość dziesiętną, gdzie „data” jest całkowitą częścią wartości dziesiętnej, a „czas” jest ułamkiem wartość. Tak więc 1900-01-01 00:00:00 jest przechowywany jako 0,0, a 20 września 2016 09:34:00 jest przechowywany jako 42631.39861. 42631 to liczba dni od 1900-01-01. .39861 to część czasu, która upłynęła od północy. Nie używaj do tego bezpośrednio typu dziesiętnego, użyj jawnego typu daty / godziny; mój punkt tutaj jest tylko ilustracją.
Przechowywanie danych w dwóch osobnych kolumnach oznacza, że będziesz musiał połączyć obie wartości kolumn za każdym razem, gdy chcesz sprawdzić, czy dany punkt w czasie jest wcześniejszy czy późniejszy niż zapisana wartość.
Jeśli przechowujesz wartości osobno, niezmiennie napotkasz „trudne” błędy, które są trudne do wykrycia. Weźmy na przykład:
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');
W powyższym kodzie tworzymy tabelę testową, zapełniając ją dwiema wartościami, a następnie wykonując proste zapytanie względem tych danych. Pierwszy SELECT
zwraca oba wiersze, jednak drugi SELECT
zwraca tylko jeden wiersz, co może nie być pożądanym rezultatem:
Prawidłowy sposób filtrowania zakresu dat / godzin, w którym wartości znajdują się w osobnych kolumnach, jak wskazał @ypercube w komentarzach, to:
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')
)
Jeśli potrzebujesz komponentu czasu oddzielonego do celów analizy , możesz rozważyć dodanie obliczonej, utrwalonej kolumny dla części czasowej wartości:
ALTER TABLE #DT
ADD dt_value_time AS CONVERT(TIME(0), dt_value) PERSISTED;
SELECT *
FROM #dt;
Utrwalona kolumna może być następnie zaindeksowana, umożliwiając szybkie sortowanie itp. Według pory dnia.
Jeśli zastanawiasz się nad podzieleniem daty i godziny na dwa pola do celów wyświetlania, powinieneś zdawać sobie sprawę, że formatowanie powinno być wykonywane na kliencie, a nie na serwerze.