Overblog
Editer l'article Suivre ce blog Administration + Créer mon blog
20 septembre 2013 5 20 /09 /septembre /2013 14:27

Il y a des fois, on agit avant de penser.

Au moment même où je validais ma requête, j'attendais un "ORA-00918: column ambiguously defined".

Mais ce n'est pas arrivé.

 

1) Les données de test

 

Précision : on est en version 10.2.0.4.0

 

create table testeuh as 

select 'a' id, 1 val from dual union all

select 'b' id, 2 val from dual;

 

create table testeuh1 as 

select 'a' id, 1 val from dual union all

select 'b' id, 2 val from dual;

 

create table testeuh2 as

select 'a' ida, 'b' idb, 0 val from dual

 

2) Ce qu'il nous arrive en général

 

Quand dans une requête sur plusieurs tables, on ne préfixe pas par l'alias de la table une colonne présente dans plusieurs tables, cela donne : 

 

SELECT val

FROM testeuh2 a

JOIN testeuh b on a.ida = b.id;

 

SELECT val

       *

ERROR at line 1:

ORA-00918: column ambiguously defined

 

Normal, car comment savoir quelle colonne val doit être renvoyée ?

Il faut donc préfixer les colonnes avec l'alias de la table : 

 

SELECT a.val

FROM testeuh2 a

  JOIN testeuh b on a.ida = b.id;

 

       VAL

----------

         0

 

3) Parce que plus on est de fous, plus on rit

 

SELECT val

FROM testeuh2 a

  JOIN testeuh b on a.ida = b.id

  JOIN testeuh1 c on a.idb = c.id;

 

       VAL

----------

         2

 

=> Ce coup-ci, la requête ne plante pas, et Oracle me renvoie arbitrairement le val de la table testeuh1... comment est-il choisi ?

 

On ne peut pas affirmer grand chose, mais on peut faire joujou : 

 

SELECT val

FROM testeuh2 a

  JOIN testeuh b on a.ida = b.id

  JOIN testeuh1 c on a.idb = c.id

  JOIN testeuh1 d on a.ida = d.id;

 

       VAL

----------

         1

 

=> Quand on rajoute une jointure de plus, ça ne plante toujours pas. De plus, c'est la dernière table citée dans la clause FROM qui remporte la mise.

 

Est-ce que cela dépend du plan d'exécution ?

 

SELECT /*+leading(b a d c)*/val

FROM testeuh2 a

  JOIN testeuh b on a.ida = b.id

  JOIN testeuh1 c on a.idb = c.id

  JOIN testeuh1 d on a.ida = d.id;

 

       VAL

----------

         1

 

Elapsed: 00:00:00.01

 

Execution Plan

----------------------------------------------------------

Plan hash value: 162124344

 

---------------------------------------------------------------------------------

| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------

|   0 | SELECT STATEMENT     |          |     1 |    43 |    14  (15)| 00:00:01 |

|*  1 |  HASH JOIN           |          |     1 |    43 |    14  (15)| 00:00:01 |

|*  2 |   HASH JOIN          |          |     1 |    37 |    10  (10)| 00:00:01 |

|*  3 |    HASH JOIN         |          |     1 |    18 |     7  (15)| 00:00:01 |

|   4 |     TABLE ACCESS FULL| TESTEUH  |     2 |    12 |     3   (0)| 00:00:01 |

|   5 |     TABLE ACCESS FULL| TESTEUH2 |     1 |    12 |     3   (0)| 00:00:01 |

|   6 |    TABLE ACCESS FULL | TESTEUH1 |     2 |    38 |     3   (0)| 00:00:01 |

|   7 |   TABLE ACCESS FULL  | TESTEUH1 |     2 |    12 |     3   (0)| 00:00:01 |

---------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   1 - access("A"."IDB"="C"."ID")

   2 - access("A"."IDA"="D"."ID")

   3 - access("A"."IDA"="B"."ID")

 

=> Et ben non, la table c est accédée en dernier, mais pour autant val ne vaut pas 2.

 

4) Conclusions

 

a. C'est une bonne pratique de préfixer systématiquement les colonnes (et en plus ça apporte énormément de lisibilité pour toute personne qui lit le code sans connaître le modèle par coeur)

 

b. "Ambiguously" provient probablement du préfixe latin amb-, qui porte l'idée de double selon wiktionary.org. Donc à partir de 3, on n'est plus ambigu, et il ne s'agit donc pas d'un bug

Partager cet article
Repost0

commentaires