Olá amiguinhos,
Esse é mais um post da Série “Casos do Dia a Dia” onde tivemos um problema em um cliente causado pela alteração no idioma da sessão da query. Você sabe os impactos que podem ser causados por essa alteração?
Espero que ao final desse post você entenda um pouco mais os conceitos dos idiomas e formatos das datas no SQL Server. Então vamos lá! #gogogo
Conceitos Básicos – Idiomas e formatos das datas:
Em primeiro lugar, vamos introduzir alguns conceitos básicos.
O comando SET LANGUAGE define o idioma da sessão:
1 |
SET LANGUAGE 'Language' |
O idioma da sessão determina os formatos das datas e as mensagens do sistema.
sys.syslanguages:
A view sys.syslanguages retorna algumas informações sobre cada um dos idiomas:
1 |
SELECT * FROM sys.syslanguages |
OBS: Reparem que o formato das datas (“dateformat”) de alguns idiomas são diferentes e iremos falar sobre isso logo mais.
sp_helplanguage:
A procedure sp_helplanguage também retorna as mesmas informações da view anterior. Nela você pode informar um idioma específico usando o texto das colunas “name” ou “alias”. Se você não informar nenhum parâmetro, ela irá retornar as informações de todos os idiomas.
1 2 3 4 5 6 7 |
-- Retorna um idioma específico EXEC sp_helplanguage us_english EXEC sp_helplanguage English -- Retorna todos os idiomas EXEC sp_helplanguage |
@@LANGUAGE:
A variável @@LANGUAGE retorna o nome do idioma que está sendo usado na sessão atual.
1 |
SELECT @@LANGUAGE AS 'Language Name' |
SET DATEFORMAT:
O comando SET DATEFORMAT define a ordem (dia, mês e ano) do formato da data da sessão atual para interpretar cadeias de caracteres de data. Os formatos mais comuns são:
English -> mdy (month / day / year)
Portuguese -> dmy (day / month / year)
Reparem que nesse exemplo nós precisamos inverter o dia e o mês na string da data de acordo com o formato que foi definido.
1 2 3 4 5 6 7 8 9 |
-- Set date format to day/month/year. SET DATEFORMAT dmy; DECLARE @Dt_Referencia DATETIME = '29/01/2020'; SELECT @Dt_Referencia AS Dt_Referencia; GO -- Set date format to month/day/year. SET DATEFORMAT mdy; DECLARE @Dt_Referencia DATETIME = '01/29/2020'; SELECT @Dt_Referencia AS Dt_Referencia; |
SYS.MESSAGES:
A view sys.messages retorna as mensagens de erro de sistema para todos os idiomas.
1 |
SELECT * FROM sys.messages |
No exemplo abaixo, nós alteramos o idioma e fizemos uma divisão por zero para gerar um erro na query. Repare como as mensagens ficam diferentes de acordo com o idioma da sessão.
1 2 3 4 5 6 7 |
-- Inglês SET LANGUAGE English; SELECT 1/0 GO -- Português SET LANGUAGE Portuguese; SELECT 1/0 |
DBCC USEROPTIONS:
O comando DBCC USEROPTIONS retorna as configurações da sessão atual (opções SET ativas). Isso pode ser muito útil para validar a sessão quando estamos investigando algum problema. Segue abaixo um exemplo:
1 |
DBCC USEROPTIONS |
Agora chega de falar sobre os conceitos básicos e vamos ao nosso problema inicial!
Problema – Alteração idioma ou formato das datas:
Um dos nossos clientes informou que o banco de dados teve um comportamento estranho na noite anterior, mas que pela manhã já estava tudo normal. Uma rotina específica teve alguns problemas no formato das datas que foram geradas em um arquivo TXT que é exportado pela aplicação e também gerou alguns erros no processo.
“The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.”
Com isso, fizemos algumas análises:
- Nenhum JOB tinha sido impactado, todos executaram normalmente no período informado;
- Não encontramos nenhuma mensagem no Error Log do SQL Server;
- No XEvent de Erros do Banco de Dados também não tinha nenhuma mensagem de erro;
- Não tinha nenhum erro no Event Viewer.
“Caramba Luiz, que macumba foi essa???”
Como o problema era no formato da data, verificamos também se teve alguma alteração no idioma do servidor do banco de dados. Nada! Pedimos para eles validarem isso no servidor da aplicação, nada também!
OBS: Segue abaixo o caminho desse log do windows e um exemplo de como fazer essa validação:
Event Viewer -> Applications and Services Logs -> Microsoft -> Windows -> International -> Operational
No dia seguinte, o cliente informou que o problema voltou a acontecer no mesmo horário. Com isso, tentamos identificar mais algumas coisas, mas sem sucesso.
Algumas horas depois, o cliente informou que conseguiu resolver o problema!
“Boa, e qual foi a bruxaria dessa vez???”
Ele informou que era uma rotina nova e identificou que ela estava alterando o idioma para “Português”, e depois disso os processos começavam a falhar. Ou seja, estava alterando o idioma sem necessidade! Com isso, eles fizeram os devidos ajustes, retiraram o trecho que fazia essa alteração e a rotina voltou a executar com sucesso!!!
Testes – Alteração idioma ou formato das datas:
Para finalizar, vamos fazer alguns testes para verificar os impactos da alteração do idioma na prática. Iremos comparar os idiomas português e inglês.
Texto Datas:
No exemplo abaixo, nós retornamos o nome do mês e o dia da semana.
1 2 3 4 5 6 7 8 9 |
DECLARE @Today DATETIME; SET @Today = '29/01/2020'; -- Inglês SET LANGUAGE us_english; SELECT @Today, convert(varchar,@Today,103) SET LANGUAGE portuguese; SELECT @Today, convert(varchar,@Today,103) |
Erro Conversão Data:
Por fim, quero mostrar um dos impactos que afetou o nosso cliente. Ao alterar o idioma ou o formato das datas, o SQL Server pode apresentar alguns erros ao tentar converter uma string para o tipo data. No caso abaixo, temos um erro quando o idioma está em Inglês, pois o formato da data é “mdy” e não existe o mês 29.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
-- Português SET LANGUAGE Portuguese; DECLARE @Dt_Referencia DATETIME = '29/01/2020'; GO -- Inglês SET LANGUAGE English; DECLARE @Dt_Referencia DATETIME = '29/01/2020'; /* Msg 242, Level 16, State 3, Line 195 The conversion of a varchar data type to a datetime data type resulted in an out-of-range value. */ GO -- Set date format to month/day/year. SET DATEFORMAT dmy; DECLARE @Dt_Referencia DATETIME = '29/01/2020'; GO -- Set date format to month/day/year. SET DATEFORMAT mdy; DECLARE @Dt_Referencia DATETIME = '29/01/2020'; /* Msg 242, Level 16, State 3, Line 180 The conversion of a varchar data type to a datetime data type resulted in an out-of-range value. */ |
Conclusão:
Portanto, tenha MUITO CUIDADO ao alterar o idioma ou o formato da data de uma sessão, pois isso pode gerar resultados incorretos ou até mesmo alguns erros!
Faça esse tipo de alteração apenas em alguns casos específicos e quando estiver ciente de todos os impactos que isso pode causar, caso contrário, utilize as configurações default da sessão para evitar problemas.
Referências:
Segue abaixo alguns links que foram utilizados como referência:
https://docs.microsoft.com/pt-br/sql/t-sql/functions/language-transact-sql?view=sql-server-ver15
Espero que tenha gostado e que isso também possa ser útil no seu dia a dia. Até o próximo post!
Me siga no LinkedIn e YouTube para ficar por dentro das novidades.
Abraço,
Luiz Vitor França Lima
Consultor SQL Server