sql >> Database >  >> RDS >> Sqlserver

Problemen oplossen bij het werken met datum en tijd in SQL Server

De Microsoft SQL Server-database slaat de datum- en tijdinformatie op in verschillende formaten. De meest voorkomende zijn DateTime , DateTime2 , en Datum . Zoals met alle soorten gegevens gebeurt, kunnen er keer op keer problemen optreden. In dit artikel zullen we ons concentreren op het oplossen van enkele van de meest voorkomende problemen waarmee u te maken kunt krijgen tijdens het werken met de SQL-gegevenstypen voor tijd en datum.

Problemen met betrekking tot regionaal verschillende datumnotaties

Het formaat van de datums varieert wereldwijd. De Britten schrijven datums bijvoorbeeld als dd-mm-jjjj, terwijl Amerikanen datums schrijven in het mm-dd-jjjj-formaat. Op deze manier wordt dezelfde datum, 31 december 2020, geschreven als 31-12-2020 in het Britse datumformaat en als 31-12-2020 in het Amerikaanse formaat.

Er kunnen onvermogensproblemen optreden als u de datum niet opgeeft in een indeling die overeenkomt met de taalinstellingen van uw SQL Server-instantie.

Het volgende script converteert de tekenreeks met de datuminformatie naar het DATETIME-formaat. De taalinstellingen zijn ingesteld op BRITISH. De tekststring bevat 31-12-2020 04:25:30 .

Als u deze tekenreeks in de DATETIME-indeling cast, wordt 31 als dag beschouwd, terwijl 12 standaard als maand wordt beschouwd. De conversie zal dus succesvol zijn, zoals blijkt uit de uitvoer:

SET LANGUAGE BRITISH;
DECLARE @date VARCHAR(50) = '31-12-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

Als u echter probeert de tekenreeks met de datum 31-12-2020 . te converteren naar het DATETIME-formaat met behulp van de US_ENGLISH taalinstellingen, ontvangt u een foutmelding zoals hieronder weergegeven:

SET LANGUAGE US_ENGLISH;
DECLARE @date VARCHAR(50) = '31-12-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

De fout treedt op omdat de US_ENGLISH taalinstellingen 31 . definiëren als een maand in plaats van een dag. Als de maand waarde mag niet groter zijn dan 12, we ontvangen de fout buiten bereik .

Als u de datum specificeert als 31-12-2020 en vervolgens de datumreeks converteert naar DATETIME met behulp van de US_ENGLISH-instellingen, ziet u de succesvolle conversie:

SET LANGUAGE US_ENGLISH;
DECLARE @date VARCHAR(50) = '12-31-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

Evenzo, het converteren van de 31-12-2020 datumreeks onder de BRITISH-taalinstelling veroorzaakt ook een fout - 31 wordt behandeld als een maand, dat kan niet.

SET LANGUAGE BRITISH;
DECLARE @date VARCHAR(50) = '12-31-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

Om uw datum nauwkeurig om te zetten, ongeacht de taalinstellingen, kunt u de ISO-standaard 8601 voor datumnotatie gebruiken. Om aan deze norm te voldoen, specificeert u de datum als jjjj-mm-ddThh:mm:ss .

De datumreeks 2020-12-31T04:25:30 is bijvoorbeeld met succes geconverteerd naar het DATETIME-gegevenstype onder de BRITISH-taalinstellingen:

SET LANGUAGE BRITISH;
DECLARE @date VARCHAR(50) = '2020-12-31T04:25:30';
SELECT CAST(@date AS DATETIME);

Het volgende script toont dezelfde string omgezet naar DATETIME met de US_ENGLISH instellingen:

SET LANGUAGE US_ENGLISH;
DECLARE @date VARCHAR(50) = '2020-12-31T04:25:30';
SELECT CAST(@date AS DATETIME);

Overwegingen voor tijdzones

Misschien wilt u een aantal SQL Server-databasetoepassingen ontwikkelen voor het wereldwijde publiek. Daarvoor moet u mogelijk de tijdzone-informatie . toevoegen naar de datum- en tijdgegevenstypen.

In SQL Server slaat het gegevenstype DATETIMEOFFSET de datum- en tijdinformatie op samen met de tijdzone-offset. De tijdzone-offset wordt gespecificeerd als UTC +/- aantal uren.

Het volgende script gebruikt bijvoorbeeld de methode SYSDATETIMEOFFSET() om de datum, tijd en offset-informatie op te halen van het systeem waarop uw SQL Server-instantie wordt uitgevoerd. De waarden die worden geretourneerd door de functie SYSDATETIMEOFFSET() worden opgeslagen in de variabele van het type DATETIMEOFFSET @dateoffset. De waarde van de @dateoffset-variabele wordt afgedrukt met behulp van de SELECT-instructie:

DECLARE @dateoffset DATETIMEOFFSET = SYSDATETIMEOFFSET();
SELECT @dateoffset

De onderstaande output toont de huidige datum en tijd en de offsetwaarde. In dit geval is het +02:00.

U kunt ook alleen de offsetwaarde uit de variabele DATETIMEOFFSET halen. Om dit te doen, moet u de variabele van het type DATETIMEOFFSET als de tweede parameterwaarde doorgeven aan de functie DATENAME(). De eerste parameter van de DATENAME()-methode moet tzoffset . zijn .

Het volgende script retourneert het tijdsverschilgedeelte van de huidige systeemdatum:

DECLARE @dateoffset DATETIMEOFFSET = SYSDATETIMEOFFSET();
SELECT DATENAME(tzoffset, @dateoffset)

Om een ​​aangepaste DATETIMEOFFSET-variabele te maken, geeft u waarden op voor de datum-, tijd- en tijdverschuivingsgedeelten. Bijvoorbeeld, in het volgende script, de waarde voor de datum is 22-02-2015 , de waarde voor het tijdsgedeelte is 23:59:59:999 , en de tijdverschuivingswaarde is +05:00 .

DECLARE @dateoffset DATETIMEOFFSET = '2015-02-22 23:59:59:999 +05:00';
SELECT @dateoffset

Ten slotte kunt u ook de tijdverschuivingsinformatie bijwerken met de SWITCHOFFSET() functie.

U moet slagen voor de DATETIMEOFFSET typ variabele als de eerste parameterwaarde en geef de nieuwe tijdverschuiving als de tweede parameterwaarde door aan de SWITCHOFFSET functie.

Het volgende script werkt de tijdverschuivingswaarde voor de variabele DATETIMEOFFSET bij van +05:00 tot +09:00.

DECLARE @dateoffset DATETIMEOFFSET = '2015-02-22 23:59:59:999 +05:00';
SELECT SWITCHOFFSET(@dateoffset, '+09:00');

Records selecteren met BETWEEN Operator met DateTime

De TUSSEN operator in de SQL-server filtert de records tussen het waardenbereik dat eraan wordt doorgegeven.

U kunt de operator BETWEEN gebruiken om records tussen twee datums te retourneren. U moet echter extra voorzichtig zijn als u het gebruikt voor het filteren van records met datums.

Het volgende script maakt bijvoorbeeld een dummy Hostel database en voegt een Student . toe tabel ernaartoe.

CREATE DATABASE Hostel

USE Hostel
CREATE TABLE Student

(
Id INT PRIMARY KEY IDENTITY(1,1),
Name VARCHAR (50) NOT NULL,
Gender VARCHAR (50),
BirthDate DateTime
)

Het volgende script voegt enkele dummy-records toe aan de Student tafel. De Geboortedatum kolom van de Student tafel slaat datums op. Uit dit script kun je zien dat twee studenten Sara en Nik dezelfde geboortedata hebben. De geboortetijd is echter anders:

INSERT INTO Student
VALUES ('Jack', 'Male', '2017-06-30 16:30:35'),
('Sara', 'Female', '2015-02-22 00:00:00'),
('Elisa', 'Female',  '2020-03-16 22:24:39'),
('Nik', 'Male',  '2015-02-22 09:45:55'),
('Jos', 'Male',  '2015-03-25 11:55:20')

Je zou denken dat de BETWEEN-operator zou kunnen worden gebruikt om de gegevens op te halen van alle studenten die op 22-02-2015 zijn geboren.

SELECT * FROM Student
WHERE BirthDate BETWEEN '2015-02-22' AND '2015-02-22'

Maar als u het bovenstaande script uitvoert, zult u zien dat er slechts één record wordt geretourneerd, ondanks de tijd deel is ook inbegrepen.

De reden is dat de BETWEEN-operator standaard de DATETIME-waarde van 22-02-2015 behandelt. als 2015-02-22 00:00:00 . Daarom zocht de operator BETWEEN in de bovenstaande zoekopdracht naar de records met de BirthDate waarde tussen 2015-02-22 00:00:00 en 2015-02-22 00:00:00 .

Om dit probleem op te lossen, moeten we het tijdsgedeelte specificeren wanneer we de BETWEEN-operator gebruiken met het gegevenstype DATETIME.

Het volgende script retourneert alle records tussen 2015-02-22 00:00:00 en 2015-02-22 23:59:59:999 . Het tijdsgedeelte voor de bovenste datumlimiet is 23:59:999.

SELECT * FROM Student
WHERE BirthDate BETWEEN '2015-02-22' AND '2015-02-22 23:59:59:999';

In de uitvoer krijgen we twee records voor de BirthDate 22-02-2015 .

Problemen met betrekking tot datumbereiken

Het gegevenstype DATETIME ondersteunt alleen de jaren 1753 tot en met 9999. Als u daarom een ​​datum probeert op te slaan met een jaarwaarde groter dan 9999 of kleiner dan 1753, krijgt u een foutmelding.

Het volgende script probeert de 1392-12-31 . te converteren datum string. 1392 is kleiner dan 1753. We hebben dus de waarde buiten bereik.

DECLARE @date VARCHAR(50) = '1392-12-31 04:25:30';
SELECT CAST(@date AS DATETIME);

Jaarwaarden opslaan minder dan 1753 , kunt u de DATETIME2 . gebruiken data type. Het slaat jaarwaarden op van 0000 tot 9999.

Het volgende script converteert de datumreeks 1392-12-31 met succes naar het gegevenstype DATETIME2:

DECLARE @date VARCHAR(50) = '1392-12-31 04:25:30';
SELECT CAST(@date AS DATETIME2);

TRY_COVERT gebruiken voor DateTime-conversie

De CONVERT-functie in SQL Server converteert de gegevens van het ene type naar het andere. U kunt het gebruiken voor het converteren van dataformaten van het datumtype naar andere formaten en vice versa. Als de conversie echter mislukt, geeft de CONVERT-functie een foutmelding.

We converteren bijvoorbeeld de tekenreeks 31-31-2015 naar DATETIME formaat:

DECLARE @date VARCHAR(50) = '2015-31-13';
SELECT  CONVERT(DATETIME, @date ,105) as DOB_CONV

Als u een NULL-waarde wilt retourneren wanneer de conversie mislukt in plaats van het foutbericht, gebruikt u de TRY_CONVERT functie. Deze methode laat de applicatie niet crashen - het retourneert gewoon een NULL-waarde.

DECLARE @date VARCHAR(50) = '2015-31-13';

SELECT  TRY_CONVERT(DATETIME, @date ,105) as DOB_CONV

Conclusie

Als u met SQL Server werkt, kunt u met veel problemen worden geconfronteerd die uw ervaring bederven en de taken ingewikkelder maken. Aan de andere kant is het kennen van de meest voorkomende problemen de meest efficiënte methode om ze te voorkomen. Daarom hebben we dit artikel gewijd aan het oplossen van dergelijke ongemakken die zich tijdens uw werk kunnen voordoen met de informatie over datums en tijden.

Merk ook op dat moderne tools voor het werken met SQL Server-databases het leven van DB-specialisten veel eenvoudiger kunnen maken. In het bijzonder biedt de dbForge Studio voor SQL Server de functie Visual Data Editor om toe te passen bij het omgaan met datums. U kunt het gebruiken om de datums op de meest gebruiksvriendelijke manier te bekijken en te bewerken.


  1. Oracle-verschillen tussen NVL en Coalesce

  2. "Kan de trigger niet laten vallen" Fout bij het verwijderen van een aanmeldingstrigger? Probeer dit.

  3. Hoe het SQL-queryresultaat naar PANDAS-gegevensstructuur te converteren?

  4. SqlBulkCopy invoegen met identiteitskolom