Oracle
 sql >> Base de données >  >> RDS >> Oracle

clause d'union en sql

Cette réponse peut être un peu décousue...

Oracle est très pointilleux avec des opérations définies. Chaque colonne doit avoir le même type de données que celles correspondantes dans les deuxième, troisième requêtes, etc.

Je pense votre deuxième requête échoue car Oracle évalue to_number() comme un nombre précédent pour effectuer l'union mais l'évalue pour "null-ness" après . Votre première requête réussit car la première valeur a été évaluée pour "null-ness", puis l'union se produit. Cela implique que l'ordre d'évaluation est :

  1. 1ère sélection de fonctions
  2. Première sélection des types de données
  3. 2e fonctions de sélection
  4. syndicat
  5. 2e sélectionner les types de données

Je vais essayer de le prouver étape par étape, mais je ne suis pas sûr que cela constituera une preuve absolue.

Les deux requêtes suivantes

select 1 from dual union select '1' from dual;
select '1' from dual union select 1 from dual;

échouera avec l'erreur suivante car aucune conversion implicite n'a lieu.

Cependant, les deux éléments suivants réussiront

select null from dual union select '1' from dual;
select null from dual union select 1 from dual;

Si nous sélectionnons le dump de ces deux requêtes, la suivante est renvoyée :

SQL> select dump(a)
  2    from ( select null a from dual union select '1' from dual );

DUMP(A)
-------------------------------------------------------------------

Typ=96 Len=1: 49
NULL

SQL> select dump(a)
  2    from ( select null a from dual union select 1 from dual );

DUMP(A)
-------------------------------------------------------------------

Typ=2 Len=2: 193,2
NULL

Comme vous pouvez le voir, les colonnes ont différents types de données . La première requête, avec un caractère, retourne un char et le second renvoie un nombre, mais la commande a été inversée, avec le second select venir en premier.

Enfin, si nous regardons dump de votre première requête

SQL> select substr(dump(ename),1,35) a, substr(dump(loc),1,35) b
  2    from ( select ename,to_number(null) as loc from emp
  3            union
  4           select to_char(null),loc from dept
  5                  );

A                                   B
----------------------------------- -----------------------------------
Typ=1 Len=6: 104,97,104,97,104,97   NULL
NULL                                Typ=1 Len=6: 104,97,104,97,104,97

SQL>

Vous pouvez voir que dump(to_number(null)) est nul ; mais un varchar2 pas un char est renvoyé, car il s'agit du type de données de votre colonne. Il est intéressant de noter que l'ordre des instructions renvoyées n'a pas été inversé et que si vous deviez créer cette requête en tant que table, les deux colonnes seraient un varchar2 .

Lors de la décision du type de données d'une colonne dans une requête de sélection, Oracle prend le premier type de données connu, puis l'utilise pour calculer le type de données global. Ce serait pourquoi les requêtes où le premier select était null avaient leurs lignes inversées.

Votre première requête réussit car la première sélection, select ename,to_number(null) from emp , "décrit" à quoi ressemblera le jeu de résultats. |varchar2|null| . La deuxième requête ajoute alors, |varchar2|varchar2| , ce qui ne pose aucun problème.

Votre deuxième requête échoue car la première sélection select ename,to_number(null) from emp "décrit" le jeu de résultats comme varchar2, null . Cependant, vous essayez ensuite d'ajouter un nombre nul et un varchar2 dans le union .

L'acte de foi ici est qu'Oracle décide que to_number(null) est un nombre antérieur au union et ne pas l'évaluer pour la "nullité" jusqu'à après. Je ne sais pas vraiment comment tester si cela se produit réellement car vous ne pouvez pas créer un objet avec un null colonne et comme vous le notez, vous ne pouvez pas le sélectionner non plus.

Comme je ne peux pas prouver quelque chose qu'Oracle interdit, je vais essayer d'obtenir des preuves empiriques. Tenez compte des résultats (ou des erreurs) des requêtes suivantes.

SQL> select 1 as a from dual union select to_number(null) from dual;

         A
----------
         1


SQL> select '1' as a from dual union select to_number(null) from dual;
select '1' as a from dual union select to_number(null) from dual
       *
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression


SQL> select 1 as a from dual union select to_char(null) from dual;
select 1 as a from dual union select to_char(null) from dual
       *
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression


SQL> select '1' as a from dual union select to_char(null) from dual;

A
-
1

Ils semblent démontrer que to_char et to_number , qu'ils soient exécutés sur un null définissent implicitement un type de données qui est ensuite évalué pour sa pertinence dans une union , avant leur évaluation pour "null-ness"

Cette explication couvrirait également la coalesce issue comme to_number(null) est un nombre devant c'est un nul.