Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Solucionando problemas ao trabalhar com data e hora no SQL Server


O banco de dados do Microsoft SQL Server armazena as informações de data e hora em vários formatos. Os mais comuns são DateTime , DataHora2 e Data . Como acontece com todos os tipos de dados, os problemas podem ocorrer vez após vez. Neste artigo, vamos nos concentrar na solução de alguns dos problemas mais comuns que você pode enfrentar ao trabalhar com os tipos de dados de data e hora do SQL.

Problemas relacionados a formatos de datas regionalmente diferentes


O formato das datas varia globalmente. Por exemplo, os britânicos escrevem datas como dd-mm-aaaa, enquanto os americanos escrevem datas no formato mm-dd-aaaa. Desta forma, a mesma data, 31 de dezembro de 2020, é escrita como 31-12-2020 no formato de data britânico e como 31-12-2020 no formato americano.

Podem surgir problemas de incapacidade se você não especificar a data em um formato correspondente às configurações de idioma de sua instância do SQL Server.

O script a seguir converte a string de texto com as informações de data no formato DATETIME. As configurações de idioma estão definidas para BRITISH. A string de texto contém 31-12-2020 04:25:30 .

Se você converter essa string no formato DATETIME, 31 será tratado como dia, enquanto 12 será mês por padrão. Portanto, a conversão será bem-sucedida, conforme mostrado na saída:
SET LANGUAGE BRITISH;
DECLARE @date VARCHAR(50) = '31-12-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

No entanto, se você tentar converter a string que contém a data 31-12-2020 para o formato DATETIME usando o US_ENGLISH configurações de idioma, você receberá um erro conforme mostrado abaixo:
SET LANGUAGE US_ENGLISH;
DECLARE @date VARCHAR(50) = '31-12-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

O erro ocorre porque as configurações de idioma US_ENGLISH definem 31 como um mês em vez de um dia. Como o mês valor não pode ser maior que 12, estamos recebendo o erro de valor fora do intervalo .

Se você especificar a data como 31-12-2020 e depois converter a string de data para DATETIME usando as configurações US_ENGLISH, verá a conversão bem-sucedida:
SET LANGUAGE US_ENGLISH;
DECLARE @date VARCHAR(50) = '12-31-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

Da mesma forma, converter o 31-12-2020 string de data na configuração de idioma BRITÂNICO também causa um erro – 31 é tratado como um mês, isso não pode ser.
SET LANGUAGE BRITISH;
DECLARE @date VARCHAR(50) = '12-31-2020 04:25:30';
SELECT CAST(@date AS DATETIME);

Para converter sua data com precisão, independentemente das configurações de idioma, você pode usar o padrão ISO 8601 para formato de data. Para cumprir com este padrão, especifique a data como aaaa-mm-ddThh:mm:ss .

Por exemplo, a string de data 2020-12-31T04:25:30 é convertida com sucesso para o tipo de dados DATETIME nas configurações de idioma BRITISH:
SET LANGUAGE BRITISH;
DECLARE @date VARCHAR(50) = '2020-12-31T04:25:30';
SELECT CAST(@date AS DATETIME);

O script a seguir mostra a mesma string convertida em DATETIME com as configurações US_ENGLISH:
SET LANGUAGE US_ENGLISH;
DECLARE @date VARCHAR(50) = '2020-12-31T04:25:30';
SELECT CAST(@date AS DATETIME);

Considerações de fuso horário


Você pode querer desenvolver alguns aplicativos de banco de dados SQL Server para o público global. Para isso, pode ser necessário adicionar as informações de fuso horário aos tipos de dados de data e hora.

No SQL Server, o tipo de dados DATETIMEOFFSET armazena as informações de data e hora junto com o deslocamento de fuso horário. O deslocamento de fuso horário é especificado como UTC +/- número de horas.

Por exemplo, o script a seguir usa o método SYSDATETIMEOFFSET() para obter as informações de data, hora e deslocamento do sistema que executa sua instância do SQL Server. Os valores retornados pela função SYSDATETIMEOFFSET() são armazenados na variável do tipo DATETIMEOFFSET @dateoffset. O valor da variável @dateoffset é impresso usando a instrução SELECT:
DECLARE @dateoffset DATETIMEOFFSET = SYSDATETIMEOFFSET();
SELECT @dateoffset

A saída abaixo mostra a data e hora atuais e o valor de deslocamento. Neste caso, é +02:00.

Você também pode obter apenas o valor de deslocamento da variável DATETIMEOFFSET. Para fazer isso, você precisa passar a variável do tipo DATETIMEOFFSET como o segundo valor de parâmetro para a função DATENAME(). O primeiro parâmetro para o método DATENAME() deve ser tzoffset .

O script a seguir retorna a parte de deslocamento de tempo da data atual do sistema:
DECLARE @dateoffset DATETIMEOFFSET = SYSDATETIMEOFFSET();
SELECT DATENAME(tzoffset, @dateoffset)

Para criar uma variável DATETIMEOFFSET personalizada, especifique valores para as partes de data, hora e deslocamento de hora. Por exemplo, no script a seguir, o valor para a data é 22-02-2015 , o valor para a parte do tempo é 23:59:59:999 , e o valor de deslocamento de tempo é +05:00 .
DECLARE @dateoffset DATETIMEOFFSET = '2015-02-22 23:59:59:999 +05:00';
SELECT @dateoffset

Por fim, você também pode atualizar as informações de deslocamento de tempo usando o SWITCHOFFSET() função.

Você precisa passar o DATETIMEOFFSET digite variável como o primeiro valor de parâmetro e passe o novo deslocamento de tempo como o segundo valor de parâmetro para o SWITCHOFFSET função.

O script a seguir atualiza o valor de deslocamento de tempo para a variável DATETIMEOFFSET de +05:00 para +09:00.
DECLARE @dateoffset DATETIMEOFFSET = '2015-02-22 23:59:59:999 +05:00';
SELECT SWITCHOFFSET(@dateoffset, '+09:00');

Selecionando registros usando o operador BETWEEN com DateTime


O ENTRE O operador no servidor SQL filtra os registros entre o intervalo de valores passados ​​a ele.

Você pode usar o operador BETWEEN para retornar registros entre duas datas. No entanto, você deve ter cuidado extra ao usá-lo para filtrar registros com datas.

Por exemplo, o script a seguir cria um Hostel fictício banco de dados e adiciona um Aluno mesa para isso.
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
)

O próximo script adiciona alguns registros fictícios ao Aluno tabela. A Data de Nascimento coluna do Aluno tabela armazena datas. A partir deste roteiro, você pode ver que dois alunos, Sara e Nik, têm as mesmas datas de nascimento. No entanto, a hora do nascimento é diferente:
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')

Você pensaria que o operador BETWEEN poderia ser usado para recuperar os registros de todos os alunos nascidos em 22-02-2015.
SELECT * FROM Student
WHERE BirthDate BETWEEN '2015-02-22' AND '2015-02-22'

Mas se você executar o script acima, verá que apenas um registro é retornado, apesar do tempo parte também está incluído.

O motivo é que o operador BETWEEN trata por padrão o valor DATETIME de 2015-02-22 como 2015-02-22 00:00:00 . Portanto, o operador BETWEEN na consulta acima pesquisou os registros com a BirthDate valor entre 22-02-2015 00:00:00 e 22-02-2015 00:00:00 .

Para resolver esse problema, devemos especificar a parte do tempo ao usar o operador BETWEEN com o tipo de dados DATETIME.

O script a seguir retornará todos os registros entre 2015-02-22 00:00:00 e 22/02/2015 23:59:59:999 . A parte do tempo para o limite máximo de data é 23:59:999.
SELECT * FROM Student
WHERE BirthDate BETWEEN '2015-02-22' AND '2015-02-22 23:59:59:999';

Na saída, obtemos dois registros para a BirthDate 22-02-2015 .

Problemas relacionados a intervalos de datas


O tipo de dados DATETIME oferece suporte apenas aos anos 1753 a 9999. Portanto, se você tentar armazenar uma data com um valor de ano maior que 9999 ou menor que 1753, receberá um erro.

O script a seguir tenta converter o 1392-12-31 seqüência de data. 1392 é menor que 1753. Portanto, temos o erro de valor fora do intervalo.
DECLARE @date VARCHAR(50) = '1392-12-31 04:25:30';
SELECT CAST(@date AS DATETIME);

Para armazenar valores de ano inferiores a 1753 , você pode usar o DATETIME2 tipo de dados. Ele armazena valores de ano de 0000 a 9999.

O script a seguir converte com sucesso a string de data 1392-12-31 para o tipo de dados DATETIME2:
DECLARE @date VARCHAR(50) = '1392-12-31 04:25:30';
SELECT CAST(@date AS DATETIME2);

Usando TRY_COVERT para conversão de data e hora


A função CONVERT no SQL Server converte os dados de um tipo para outro. Você pode usá-lo para converter os formatos de dados do tipo data para outros formatos e vice-versa. No entanto, se a conversão falhar, a função CONVERT gera um erro.

Por exemplo, estamos convertendo a string 2015-31-31 para o formato DATETIME:
DECLARE @date VARCHAR(50) = '2015-31-13';
SELECT  CONVERT(DATETIME, @date ,105) as DOB_CONV

Se desejar que um valor NULL seja retornado quando a conversão falhar em vez da mensagem de erro, use o TRY_CONVERT função. Este método não deixa o aplicativo travar – ele simplesmente retorna um valor NULL.
DECLARE @date VARCHAR(50) = '2015-31-13';

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

Conclusão


Ao trabalhar com o SQL Server, você pode enfrentar muitos problemas, prejudicando sua experiência e complicando as tarefas. Conhecer os problemas mais comuns é, por outro lado, o método mais eficiente para evitar que eles aconteçam. É por isso que dedicamos este artigo para solucionar esses inconvenientes que podem ocorrer durante o seu trabalho com as informações sobre datas e horários.

Observe também que ferramentas modernas para trabalhar com bancos de dados SQL Server podem tornar a vida dos especialistas em banco de dados muito mais simples. Em particular, o dbForge Studio for SQL Server fornece o recurso Visual Data Editor para aplicar ao lidar com datas. Você pode usá-lo para visualizar e editar as datas da maneira mais amigável.