Canalblog
Editer l'article Suivre ce blog Administration + Créer mon blog
Publicité
Blog d'un DBA sur le SGBD Oracle et SQL
10 juillet 2018

Problème de caractères spéciaux et d'accents dans le nom d'objets - Problem of special characters and accents in object names


Introduction
Dans tout logiciel ou langage informatique, il existe des caractères spéciaux. En général il faut les manipuler avec précaution sinon vous risquez d'avoir de très très mauvaises surprises. Nous allons voir cela avec le nom des objets sous Oracle.



 

Points d'attention
NA.


 

Base de tests
N'importe quelle base Oracle; tests sur une 12.1.

 


 

Exemples
============================================================================================
Nom de table avec des caractères spéciaux
============================================================================================
Oracle autorise, dans les noms d'objets, les caractères spéciaux suivants $ # et _ avec en plus @ et . pour les dblinks; pour les autres caractères spéciaux, il faut utiliser des guillemets.

Premier test : nom d'une table avec les caractères spéciaux autorisés; pas besoin de guillemets.
     SQL> create table A$#_ (id number);
     Table created.
     
Si on utilise d'autres caractères spéciaux, guillemets obligatoires; exemple d'un nom de colonne.
     SQL> CREATE TABLE test02 (a$^*$ VARCHAR2(10));
     CREATE TABLE test02 (a$^*$ VARCHAR2(10))
                            *
     ERROR at line 1:
     ORA-00902: invalid datatype
    
     SQL> CREATE TABLE test02 ("a$^*$" VARCHAR2(10));
     Table created.

On voit que le nom de la colonne est correctement stocké, avec les caractères spéciaux saisis.
     SQL> desc test02
     Name        Null?    Type
     ----------------------------
     a$^*$                 VARCHAR2(10)
    
     SQL> SELECT COLUMN_NAME from user_tab_cols where TABLE_NAME = 'TEST02';
     COLUMN_NAME
     --------------
     a$^*$
    
     SQL> insert into test02 values ('TEST');
     1 row created.
     
     SQL> commit;
     Commit complete.
    
Ah, problème si on veut utiliser le nom de la colonne, il faut là aussi les guillemets. Et oui, c'est le piège : vous devez TOUJOURS utiliser les guillemets si vous avez décidé de contourner les règles de nommage d'Oracle :-)  Vous voilà prévenus, EVITEZ AU MAXIMUM de contourner ces règles, même si Oracle le permet de façon documentée avec ces fameux guillemets : vous allez au devant de mauvaises surprises!

Vous avez aussi noté que dans le dictionnaire de données il n'y a pas de guillemets, alors si vous récupérez via une requête SQL la liste des tables ou colonnes de votre schéma, vous risquez d'avoir un message du style "Table inconnue" alors qu'elle existe bien dans le dictionnaire...
     SQL> select a$^*$ from test02;
     select a$^*$ from test02
              *
     ERROR at line 1:
     ORA-00923: FROM keyword not found where expected
    
     SQL> select "a$^*$" from test02;
     a$^*$
     ----------
     TEST


============================================================================================
Nom d'objet et accents : aïe, là c'est plus bizarre!
============================================================================================
Maintenant nous allons faire un autre test et utiliser, non pas un caractère spécial mais un caractère accentué qui ne fait pas partie du langage de la base, même s'il fait partie du character set de celle-ci. En bref, ma base est en anglais et je vais utiliser le caractère ù qui fait partie du jeu de données Unicode de ma base mais pas de l'anglais.

Vous noterez que je n'ai pas besoin de mettre les guillemets pour créer le nom de ma colonne. Néanmoins, pour utiliser ce nom, ça va être plus compliqué qu'avec un caractère spécial.
Ma base est en américain, character set UTF8.
     SQL> select parameter, value from v$nls_parameters order by parameter;
     PARAMETER                             VALUE
     ----------------------------------------------------------------
     NLS_CALENDAR                             GREGORIAN
     NLS_CHARACTERSET                         AL32UTF8
     NLS_COMP                             BINARY
     NLS_CURRENCY                             $
     NLS_DATE_FORMAT                          DD-MON-RR
     NLS_DATE_LANGUAGE                         AMERICAN
     NLS_DUAL_CURRENCY                         $
     NLS_ISO_CURRENCY                         AMERICA
     NLS_LANGUAGE                             AMERICAN
     NLS_LENGTH_SEMANTICS                         BYTE
     NLS_NCHAR_CHARACTERSET                         AL16UTF16
     NLS_NCHAR_CONV_EXCP                         FALSE
     NLS_NUMERIC_CHARACTERS                         .,
     NLS_SORT                             BINARY
     NLS_TERRITORY                             AMERICA
     NLS_TIMESTAMP_FORMAT                         DD-MON-RR HH.MI.SSXFF AM
     NLS_TIMESTAMP_TZ_FORMAT                      DD-MON-RR HH.MI.SSXFF AM TZR
     NLS_TIME_FORMAT                          HH.MI.SSXFF AM
     NLS_TIME_TZ_FORMAT                         HH.MI.SSXFF AM TZR
     
     19 rows selected.

Je crée une table avec une colonne appelée ù
     SQL> CREATE TABLE testaccent (ù VARCHAR2(10));

     Table created.
     
Et voilà le problème! Le ù a été transformé en deux ?? dans le dictionnaire de données.
Pourtant ù est connu du character set UTF8.
     SQL> desc testaccent
     Name            Null?   Type
     ---------------- ---------------------
     ??                        VARCHAR2(10)
    
Attention, si je peux saisir un ù à l'écran de mon PC, je suis du côté du client (pc windows 7) mais ma base est en américain et donc ne connaît pas le ù, ce qui explique pourquoi Oracle ne stocke pas le ù dans la base.
     SQL> SELECT COLUMN_NAME from user_tab_cols where TABLE_NAME = 'TESTACCENT';
     COLUMN_NAME
     ------------
     ??
    
     SQL> insert into testaccent values ('TEST');
     1 row created.
    
     SQL> commit;
     Commit complete.

Le nom de la colonne pose problème...    
     SQL>  select ù from testaccent;
     select ù from testaccent
            *
     ERROR at line 1:
     ORA-00904: "??": invalid identifier
    
Avec des guillemets ça ne passe pas non plus : ça devient compliqué...
     SQL> select "ù" from testaccent;
     select "ù" from testaccent
            *
     ERROR at line 1:
     ORA-00904: "??": invalid identifier

Alors là, même avec le nom de la colonne stocké en base, impossible de référencer ma colonne, même avec "", ça ne passe pas.
     SQL> SELECT ?? FROM testaccent;
     SELECT ?? FROM testaccent
            *
     ERROR at line 1:
     ORA-00911: invalid character
    
     SQL> SELECT "??" FROM testaccent;
     ERROR at line 1:
     ORA-00904: "??": invalid identifier

Même en PL/SQL ça plante : je pensais que le nom de la colonne stocké en base était différent de ?? mais que ?? était ce qui été affiché par Oracle. Hé ben non, là encore  impossible d'accéder à ma colonne.
     SQL> set serveroutput on
     
     SQL> DECLARE
         v_col_name VARCHAR2(128);
         v_select VARCHAR2(128);
     BEGIN
         SELECT COLUMN_NAME into v_col_name from user_tab_cols where TABLE_NAME = 'TESTACCENT';
         v_select := 'SELECT ' || v_col_name || ' FROM testaccent ';
         dbms_output.put_line(v_select);
         EXECUTE IMMEDIATE 'SELECT ' || v_col_name || ' FROM testaccent ';
     END;
     /  
     SELECT ?? FROM testaccent
     DECLARE
     *
     ERROR at line 1:
     ORA-00904: "??": invalid identifier
     ORA-06512: at line 8
    
Avec "", message d'erreur encore.
     SQL> DECLARE
         v_col_name VARCHAR2(128);
         v_select VARCHAR2(128);
     BEGIN
         SELECT COLUMN_NAME into v_col_name from user_tab_cols where TABLE_NAME = 'TESTACCENT';
         v_select := 'SELECT "' || v_col_name || '" FROM testaccent ';
         dbms_output.put_line(v_select);
         EXECUTE IMMEDIATE 'SELECT ' || v_col_name || ' FROM testaccent ';
     END;
     /  
     
     SELECT "??" FROM testaccent
     DECLARE
     *
     ERROR at line 1:
     ORA-00904: "??": invalid identifier
     ORA-06512: at line 8
    
Mais, alors là, le plus bizarre est que le ù est traité différemment selon qu'il est dans le nom d'une table ou d'une colonne.
     SQL> CREATE TABLE ù (ID NUMBER);
     Table created.

Le nom de la table est lui aussi ??     
     SQL> select table_name from user_tables order by 1;
     TABLE_NAME
     --------------
     A
     COUNTRIES
     DEPARTMENTS
     EMPLOYEES
     JOBS
     JOB_HISTORY
     LOCATIONS
     REGIONS
     TEST01
     TEST02
     TESTACCENT
     ??
     
     12 rows selected.

Mais on arrive quand même à l'interroger en utilisant tout simplement le caractère ù, avec guillemets ou non, alors que c'est impossible pour une colonne de même nom.    
     SQL> desc ù
     Name        Null?    Type
     -------------------------------
     ID                    NUMBER
     
     SQL> desc "ù"
     Name        Null?    Type
     -------------------------------
     ID                    NUMBER
     
Le SELECT aussi est OK.
     SQL> insert into ù values (1);
     1 row created.
     
     SQL> commit;
     Commit complete.
     
     SQL> select * from ù;
         ID
     ----------
          1

En revanche ?? reste inconnu alors que c'est ce qui est affiché dans user_tables.
     SQL> select * from ??;
     select * from ??
                   *
     ERROR at line 1:
     ORA-00911: invalid character
     
     
     SQL> select * from "??";
     select * from "??"
                   *
     ERROR at line 1:
     ORA-00942: table or view does not exist
         


J'espère que vous avez compris : ne jouez pas avec les caractères spéciaux d'Oracle et les caractères non supportés par le langage de la base.
En bref : n'utilisez que les caractères américains avec en plus $ # et _ cela vous évitera de perdre vos cheveux par poignées :-)


Publicité
Publicité
Commentaires
Blog d'un DBA sur le SGBD Oracle et SQL
Publicité
Archives
Blog d'un DBA sur le SGBD Oracle et SQL
  • Blog d'un administrateur de bases de données Oracle sur le SGBD Oracle et sur les langages SQL et PL/SQL. Mon objectif est de vous faire découvrir des subtilités de ce logiciel, des astuces, voir même des surprises :-)
  • Accueil du blog
  • Créer un blog avec CanalBlog
Visiteurs
Depuis la création 340 586
Publicité