Artykuł ten jest częścią serii Od 0 do TSQL którą znajdziesz tutaj.
Po typach tekstowych oraz liczbowych przyszła pora na omówienie typów daty i czasu. Część z Was może pomyśleć, iż datę i czas można przechowywać jako wartość liczbową? Generalnie jest to możliwe – pozbawiamy się wtedy jednak możliwości jakie oferuje użytkowanie typów przeznaczonych do tego typu danych.
W SQL Server mamy wbudowanych wiele typów związanych z datą i czasem, oto one:
- date
- datetime
- datetime2
- smalldatetime
- time
- datetimeoffset
Najprostszym z nich jest wspomniany na liście typ date. Jak można się domyśleć typ ten przechowuje datę. W ramach obiektu o tym typie możemy przechowywać daty od 0001-01-01 do 9999-12-31, gdzie jeden taki wpis zajmuje zawsze 3 bajty. Jeżeli chodzi
o format danych wstawianych do takiego pola to zależy on od ustawień serwera – jednak jeżeli podamy wartość daty w formacie ‘YYYYMMDD’ to zostanie on dostosowany do ustawień lokalnych – warto więc zapamiętać ten format i stosować go w większości przypadków.
Kolejnym równie prostym typem danych jest datetime. Jak sama nazwa wskazuje przechowuje on nie tylko datę, ale również czas. Pozwala na przechowywanie dat pochodzących z zakresu od 1753-01-01 do 9999-12-31 wraz z dowolną godziną aż do części milisekundowych. Typ ten zajmuje aż 8 bajtów co jest dosyć dużym rozmiarem.
W przypadku gdy nie jest nam potrzebna tak duża dokładność jaką oferuje nam datetime to warto zastosować bardzo zbliżony typ tj. smalldatetime, który zajmuje 4 bajty ale pozwala na przechowywanie dat o dużo mniejszym zakresie tj. od 1900-01-01 do 2079-06-06. Jeżeli chodzi o czas to z smalldatetime tym wiąże się również bardzo ciekawa właściwość, którą postaram się zobrazować poniżej.
W ramach dowolnej bazy zadeklarujmy sobie zmienną przypiszmy do niej pełną datę i czas oraz wyświetlmy jej zawartość.
DECLARE @smalldatetime SMALLDATETIME SET @smalldatetime='20150101 23:51:51' PRINT @smalldatetime
Jaką wartość wyświetli nam SQL Server? Dosyć nieoczekiwaną:
Jan 1 2015 11:52PM
Jak widać nie ma zdefiniowanych części sekundowych godziny, a część minutowa została zaokrąglona. Jest to normalne zachowanie tego typu danych, który zawsze należy mieć w tyle głowy w momencie gdy chcemy go użyć.
Co natomiast w przypadku gdy nie jest dla nas istotna dla nas data a jedynie czas? SQL Server daje nam możliwość przechowywania samego czasu i obok wspomnianych typów mamy również typ time pozwalający przechowywać czas w oparciu o zegar 24 godzinny, aż do poziomu nanosekund. Poziom części sekund oczywiście jesteśmy w stanie kontrolować podając go jako parametr tj. np. time(7) oznacza właśnie poziom nanosekund – najbardziej szczegółowy. W zależności od szczegółowości typ ten zajmuje określoną ilość miejsca zgodnie z tabelą:
Zdefiniowany typ | (precyzja,skala) | Ilość bajtów |
time | (16,7) | 5 |
time(0) | (8,0) | 3 |
time(1) | (10,1) | 3 |
time(2) | (11,2) | 3 |
time(3) | (12,3) | 4 |
time(4) | (13,4) | 4 |
time(5) | (14,5) | 5 |
time(6) | (15,6) | 5 |
time(7) | (16,7) | 5 |
Typ ten ma szczególne zastosowanie w momencie gdy chcemy przechowywać bardzo szczegółowe dane godzinowe, lub gdy chcemy z jakichś powodów oddzielić godzinę od daty. Podobnym pod względem dokładności godziny jest typ datetime2, który jest standardowym połączeniem typów datetime i time, a co za tym idzie również pozwala na zdefiniowanie poziomu szczegółowości godziny i zajmuje maksymalnie do 8 bajtów.
Ostatnim typem jaki sobie wyjaśnimy jest typ datetimeoffset, który pozwala na zapis daty i czasu wraz z uwzględnieniem strefy czasowej. Wstawiając wartości do obiektu możemy użyć następującego domyślnego formatu YYYY-MM-DD hh:mm:ss[.nnnnnnn] [{+|-}hh:mm] czyli np. ‘2015-12-31 23:59:10 +01:00’ oznacza przesunięcie o 1 godzinę do przodu w stosunku do UTC czyli standardowego czasu europejskiego. Przesunięcie może być zdefiniowane jako godzina oscylująca od -14:00 do +14:00. Typ ten jest bardzo pomocny w przypadku gdy dane w naszej bazie obejmują różne strefy czasowe, w innym wypadku powinniśmy go unikać gdyż posiada on dokładność taką jak datetime2 powiększoną właśnie o strefy czasowe i zajmuje w zależności od szczegółowości od 8 do 10 bajtów. W następnym artykule w ramach serii zajmiemy się funkcjami dostępnymi w ramach SQL Server, które pozwalają operować na konkretnych wartościach związanych z typami danych – ZAPRASZAM!
- Avoiding Issues: Monitoring Query Pushdowns in Databricks Federated Queries - October 27, 2024
- Microsoft Fabric: Using Workspace Identity for Authentication - September 25, 2024
- Executing SQL queries from Azure DevOps using Service Connection credentials - August 28, 2024
Dzień Dobry
a jak sformatować datę , żeby była wyświetlana w takim formacie i była liczbą?
2019-08-05 12:17
(select top 1 (CAST(CAST (TZ.DATACZAS_DO as date) as varchar(10)))+’ ‘+(CAST(CAST (TZ.DATACZAS_DO as time) as varchar(5))) from T_TACHO_ZDARZENIA TZ with(nolock) where tz.ID_KIEROWCY = kierowcy.id_kierowcy order by tz.DATACZAS_DO DESC) as [Ostatnia_data_logowania]
ale to mi daje tekst 🙂
Dzięki za info
Witam,
tą datę chce Pan mieć jako liczbę? 201908051217? jeśli tak to polecam zapoznać się z funkcją FORMAT, która co prawda zwraca tekst ale można to później formatować jako liczbę.
Jak zapisać datę przed naszą erą? (BC)??????
Niestety żadeń z wbudowanych typów data/czas nie ma tak szerokiego zakresu.
W takim wypadku musimy albo trzymać rok/miesiąc/dzień w osobnych kolumnach albo stowrzyć swój własny typ na podstawie typu tekstowego:
https://docs.microsoft.com/en-us/sql/relational-databases/clr-integration-database-objects-user-defined-types/working-with-user-defined-types-in-sql-server?view=sql-server-ver15