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