Páginas

5 de nov. de 2012

Configurando National Language Support (NLS) no Oracle

Olá pessoal,
 
     No artigo de hoje vou comentar sobre como evitar a visualização ou formatação incorreta de caracteres, datas e números (também conhecida como desconfiguração de caracteres, como vejo muitos desenvolvedores comentar), que afeta muitas aplicações e que já vi muita gente buscar ajuda em fóruns. Esse problema é muito comum em aplicações desenvolvidas em qualquer linguagem de programação e SGBD, e para evitá-lo, no caso de SGBDs Oracle, é necessário entender os recursos de suporte à globalização, mais especificamente, o National Language Support ou NLS. 

     NLS pode ser usado para definir, através de parâmetros, configurações de terrritório, idioma e conjuntos de caracteres (character set) no BD ou sessão de um usuário. Essas configurações incluem a formatação de datas, números, moeda, linguagem, separador de caracteres em listas, sistema de calendário etc.
 
     Os parâmetros de NLS podem ser especificados na criação do BD, ou depois, em 4 caminhos (no cliente ou servidor) e a maior parte deles possui um valor padrão. Os itens abaixo apresentam exemplos de caminhos em que eles podem ser configurados, seguindo uma ordem de precedência, em que os itens de menor número são de mais baixa precedência, ou seja, se você configurar um parâmetro através de uma variável de ambiente (ver item 2), ele poderá ser sobrescrito por um parâmetro de sessão (ver item 3), que por sua vez, também poderá ser sobrescrito por um parâmetro de uma função SQL (ver item 4):

1- Configurando parâmetros NLS através de parâmetros de inicialização (instância) no Banco de Dados
          alter system set NLS_CALENDAR = persian scope=spfile;

2-  Configurando  parâmetros NLS  através de variáveis de ambiente no Sistema Operacional:            NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1

3-  Configurando  parâmetros NLS  através de parâmetros de sessão:
          alter session set NLS_DATE_FORMAT = 'dd/mm/yyyy'

4-  Configurando  parâmetros NLS  através de parâmetros de funções SQL:
          TO_CHAR(hiredate, 'DD/MON/YYYY', 'nls_date_language = FRENCH')



     Segue abaixo uma lista com os principais parâmetros de NLS, contendo nome e descrição do parâmetro, o valor padrão e o escopo em que ele pode ser configurado. Observe pela coluna valor padrão, que muitos parâmetros herdam valores de outros parâmetros. Por exemplo, NLS_DATE_FORMAT herda um valor do parâmetro NLS_TERRITORY:

Parâmetro
Descrição
Valor padrão
Escopo:
I=Instância,
E= Variável ambiente,
A= Sessão

NLS_CALENDAR 

Sistema de calendário

Gregorian 

I, E, A 

NLS_COMP  

Operador de comparação SQL, PL/SQL

Binary 

I, E, A 

NLS_CREDIT  

Símbolo de contabilidade de crédito

NLS_TERRITORY  

-, E, - 

NLS_CURRENCY  

Símbolo da moeda local

NLS_TERRITORY  

I, E, A 

NLS_DATE_FORMAT  

Formato de data

NLS_TERRITORY  

I, E, A 

NLS_DATE_LANGUAGE  

Linguagem para nomes de dias e meses

NLS_LANGUAGE  

I, E, A 

NLS_DEBIT  

Símbolo de contabilidade de dédito

NLS_TERRITORY  

-, E, - 

NLS_ISO_CURRENCY  

Símbolo internacional ISO da moeda

NLS_TERRITORY  

I, E, A 

NLS_LANG 

Linguagem, território e conjunto de caracteres (character set)

AMERICAN_AMERICA.
US7ASCII  

-, E, - 

NLS_LANGUAGE  

Linguagem

NLS_LANG  

I, -, A 

NLS_LENGTH_SEMANTICS  

Valor indicando como as strings são tratadas 

Byte 

I, -, A 

NLS_LIST_SEPARATOR  

Caractere separador de itens em uma lista

NLS_TERRITORY  

-, E, - 

NLS_MONETARY_CHARACTERS  

Símbolo  monetário para dólar e centavos (ou seus equivalentes) 

NLS_TERRITORY  

-, E, - 

NLS_NCHAR_CONV_EXCP  

Relata perda de dados durante uma conversão de tipos de caracteres



-, E, - 

NLS_NUMERIC_CHARACTERS  

Separador decimal e de gupo (milhar, milhão etc.)

NLS_TERRITORY  

I, E, A 

NLS_SORT  

Sequência de ordenação de caracteres

NLS_LANGUAGE  

I, E, A 

NLS_TERRITORY  

Território

NLS_LANG  

I, -, A 

NLS_TIMESTAMP_FORMAT  

Timestamp 

NLS_TERRITORY  

I, E, A 

NLS_TIMESTAMP_TZ_FORMAT  

Timestamp com Timezone 

NLS_TERRITORY  

I, E, A 

NLS_DUAL_CURRENCY  

Símbolo de moeda Dual

NLS_TERRITORY  

I, E, A



Configurando o parâmetro NLS_LANG

     Um dos principais parâmetros para configurar NLS é o parâmetro NLS_LANG. Se ele for corretamente configurado, dificilmente você precisará configurar mais algum outro parâmetro. NLS_LANG permite configurar através de uma variável de ambiente (no cliente), a linguagem,  território conjunto de caracteres que serão usados pela aplicação. 

     A linguagem especifica o idioma das mensagens Oracle, ordenação, nomes de dias e meses. Cada linguagem tem um nome único, como por exemplo: AMERICAN (valor padrão), FRENCH e GERMAN.

     O território especifica a formatação de data, moeda e números. Cada território tem um nome único, como por exemplo: AMERICA, FRANCE e CANADA. Se um território não for especificado, ele herda um valor da linguagem.
  
     O conjunto de caracteres (character set), especifica, como o próprio nome diz, o conjunto de caracteres que será usado pela aplicação cliente. Exemplos: US7ASCII, WEISO8859P1, JA16EUC. Cada linguagem tem um conjunto de caracteres associado que é configurado se um valor não for especificado em NLS_LANG.

      Os 3 valores de NLS_LANG podem ser configurados através de muitas combinações, como por exemplo:
                 NLS_LANG=AMERICAN_AMERICA.US7ASCII
                 NLS_LANG=FRENCH_CANADA.WE8DEC

Obs.: Combinações ilógicas podem ser configuradas, mas não funcionarão apropriadamente. Se por exemplo, for configurada uma especificação de linguagem Japanese usando um conjunto de caracteres Western European, tal como WE8DEC, você estará inapto a armazenar dados na linguagem Japanese, pois WE8DEC não suporta dados japoneses:
                 NLS_LANG=JAPANESE_JAPAN.WE8DEC


Testando NLS_LANG

    A configuração de NLS_LANG deve ser realizada através de uma variável de ambiente no cliente, portanto, irei demonstrar no passo-a-passo abaixo, a configuração e uso desse parâmetro em um cliente Windows que se conecta em um BD Oracle remoto. Para efetuar os testes é necessário ter o schema HR instalado (para mais informações sobre o HR, leia o artigo Instalando o schema de exemplo HR):

Passo 1- No cliente Windows abra um janela de prompt de comandos (ver Figura 1):

Figura 1 - Janela de prompt de comandos no Windows
Passo 2- Configure uma variável de ambiente com o nome NLS_LANG e valor American_America.WE8ISO8859P1 (ver Figura 2):

Figura 2 - Configurando NLS_LANG=American_America.WE8ISO8859P1

Passo 3- Conecte-se no BD remoto, através do SQL Plus, fornecendo um nome/senha de usuário válidos, que tenha acesso às tabelas do schema HR (ver Figura 3):

Figura 3 - Conectando-se no BD remoto através do SQL Plus
  
Passo 4- Execute a instrução SQL abaixo e veja que as datas e números estão formatados de acordo com o padrão americano ('dd-MON-yy'), configurado previamente através da variável NLS_LANG (ver Figura 4):
  
          SELECT  first_name, 
                           hire_date, 
                           salary,
                           ROUND(salary/12,2) 
          FROM     hr.employees
          where       rownum < 5;

Figura 4 - Executando SQL com NLS no padrão americano

Passo 5- Saia do SQL Plus e configure novamente a variável de ambiente NLS_LANG, mas desta vez, com o valor French_France.WE8ISO8859P1 (ver Figura 5) e repita novamente o Passo 3 (conexão ao BD com o SQL Plus):

Figura 5 -  Configurando NLS_LANG=French_France.WE8ISO8859P1

Passo 6- Execute novamente a instrução SQL do Passo 4 e veja que agora as datas e números estão formatados de acordo com o padrão francês ('dd/mm/yy'), e não mais no padrão americano (ver Figura 6):

Figura 6 -  Executando SQL com NLS no padrão francês

Passo 7- Para demonstrar algo mais, iremos configurar agora, no nível da sessão (via SQL Plus), o parâmetro  NLS_DATE_FORMAT,  sobrescrevendo o valor herdado do território (ver NLS_LANG configurado préviamente), para que o ano das datas seja visualizado no formato com 4 dígitos e executaremos novamente a instrução SQL do Passo 4 para ver o novo resultado (ver Figura 7): 

Figura 7 - Configurando NLS_DATE_FORMAT para exibir ano com 4 dígitos
         
     Bom pessoal, para finalizar o artigo, quando for necessário identificar quais são os parâmetros de NLS do BD, faça um SELECT na visão NLS_DATABASE_PARAMETERS. Se você precisa identificar os parâmetros de NLS da instância, consulte NLS_INSTANCE_PARAMETERS. Se você precisa identificar os parâmetros NLS da sessão de usuário atual, consulte a visão NLS_SESSION_PARAMETERS, como no exemplo abaixo:
          select * from nls_session_parameters;

Obs.: Lembre-se que parâmetros de NLS no nível da sessão sobrescrevem os parâmetros no nível da instância, que por sua vez, sobrescrevem os parâmetros no nível do BD, portanto, se quiser saber, por exemplo, o formato de data que a sua aplicação está usando, consulte NLS_SESSION_PARAMETERS.


Por hoje é só!
[]s

Referências:
   - Oracle Documentation: http://oracleonline.info/setting_nls.html
      

11 comentários:

  1. E ae Fábio,

    Muito bom esse artigo, o assunto é muito pertinente , semanas atrás tivemos um problema de NLS, pois no client que executava a query havia uma configuração específica de NLS, então colocamos um comando para alterar o NLS da session e executar a query, independente do client.

    Show de bola.

    Grande Abs.

    ResponderExcluir
  2. Pra variar...mais um bom artigo.

    abs,
    Marcio

    ResponderExcluir
  3. Muito bom o Artigo Fábio, já me ajudou em um problema que eu tinha.
    Quanto ao exportar para excel creio que era no NLS_LIST_SEPARATOR .
    Porém ainda quando eu exporto para o excel estou com problema quanto a textos com acentos.
    "Crédito" ainda acaba aparecendo como CRÉDITO

    No select mostra normalmente, o problema é ao exportar.
    Alterei os parâmetros na alter session.
    O que pode estar ocorrendo ainda?

    ResponderExcluir
    Respostas
    1. O seu problema agora é a codificação de caracteres do arquivo no EXCEL.

      Ela tem que ser compatível com o character set do BD. Em arquivos texto por exemplo vc pode salvar o arquivo usando N codificações (UTF* ou ANSI*). Vc tem que descobrir qual delas é compatível e gerar o arquivo na codificação certa!

      []s

      Excluir
  4. Bom dia estou aprendendo banco de dados oracle e me deparei com um erro
    quando tento inserir dados em campos float...estou usando o APEX do oracle e quando tento de forma visual editar os dados, os campos float estao bloqueados.... poderia ajudar
    Marcos

    ResponderExcluir
    Respostas
    1. Olá Marcos, este artigo não tem nada a ver com Apex, sugiro que você procure ajuda em algum fórum ou artigo de quem escreveu sobre "Apex". De qq modo conheço Apex, mas não sei o porquê do erro. Eu lhe responderia se soubesse a resposta.

      []s

      Excluir
  5. Bom dia!

    É possível corrigir o legado? todos os dados que já estão na base? Obrigado

    ResponderExcluir
    Respostas
    1. Sim, mas é bem trabalhoso e também arriscado perder dados. Pesquise sobre CSSCAN e CSALTER: https://oracle-base.com/articles/10g/character-set-migration.

      Excluir
  6. Parabens resolveu em uma aplicação delphi (NLS_LANG)

    ResponderExcluir
  7. Eu estou com problema no Access com banco de dados oracle.
    Todos os valores de milhar retornamultiplicado por 100. Ja mudei o NLS_LANG de
    BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252
    para
    AMERICAN_AMERICA.WE8ISO8859P1

    Mesmo assim continuo com o problema dos milhares.

    ResponderExcluir