L'utilisation de CONNECT BY LEVEL semble renvoyer trop de lignes lorsqu'elle est effectuée sur une table. Quelle est la logique derrière ce qui se passe?
En supposant le tableau suivant:
create table a ( id number );
insert into a values (1);
insert into a values (2);
insert into a values (3);
Cette requête renvoie 12 lignes ( SQL Fiddle ).
select id, level as lvl
from a
connect by level <= 2
order by id, level
Une ligne pour chacun dans le tableau A avec la valeur de la colonne LVL étant 1 et trois pour chacun dans le tableau A où la colonne LVL est 2, à savoir:
ID | LVL --- + ----- 1 | 1 1 | 2 1 | 2 1 | 2 2 | 1 2 | 2 2 | 2 2 | 2 3 | 1 3 | 2 3 | 2 3 | 2
Elle est équivalente à cette requête, qui renvoie les mêmes résultats.
select id, level as lvl
from dual
cross join a
connect by level <= 2
order by id, level
Je ne comprends pas pourquoi ces requêtes renvoient 12 lignes ou pourquoi il y a trois lignes où LVL est 2 et une seule où LVL est 1 pour chaque valeur de la colonne ID.
Augmenter le nombre de niveaux "connectés" à 3 renvoie 13 lignes pour chaque valeur d'ID. 1 où LVL est 1, 3 où LVL est 2 et 9 où LVL est 3. Cela semble suggérer que les lignes retournées sont le nombre de lignes dans le tableau A à la puissance de la valeur de LVL moins 1.
J'aurais cependant pensé que ces requêtes seraient les mêmes que les suivantes, ce qui renvoie 6 lignes
select id, lvl
from ( select level as lvl
from dual
connect by level <= 2
)
cross join a
order by id, lvl
Le documentation n'est pas particulièrement clair, pour moi, pour expliquer ce qui devrait se produire. Que se passe-t-il avec ces pouvoirs et pourquoi les deux premières requêtes ne sont-elles pas les mêmes que la troisième?
Dans la première requête, vous vous connectez uniquement au niveau. Donc, si le niveau <= 1, vous obtenez chacun des enregistrements 1 fois. Si niveau <= 2, alors vous obtenez chaque niveau 1 fois (pour le niveau 1) + N fois (où N est le nombre d'enregistrements dans le tableau). C'est comme si vous faisiez des jointures croisées, car vous ne faites que sélectionner tous les enregistrements de la table jusqu'à ce que le niveau soit atteint, sans avoir d'autres conditions pour limiter le résultat. Pour le niveau <= 3, cela se fait à nouveau pour chacun de ces résultats.
Donc pour 3 enregistrements:
Ce n'est pas vraiment une jointure croisée. Une jointure croisée ne retournerait que les enregistrements qui ont le niveau 2 dans ce résultat de requête, tandis qu'avec cette connexion, vous obtenez les enregistrements ayant le niveau 1 ainsi que les enregistrements ayant le niveau 2, résultant ainsi en 3 + 3 * 3 au lieu de simplement Enregistrement 3 * 3.
Quand connect by
est utilisé sans start with
clause et prior
opérateur, il n'y a aucune restriction sur la jonction d'une ligne enfant à une ligne parent. Et ce que fait Oracle dans cette situation, il renvoie toutes les permutations de hiérarchie possibles en connectant une ligne à chaque ligne de niveau supérieur.
SQL> select b
2 , level as lvl
3 , sys_connect_by_path(b, '->') as ph
4 from a
5 connect by level <= 2
6 ;
B LVL PH
---------- ----------
1 1 ->1
1 2 ->1->1
2 2 ->1->2
3 2 ->1->3
2 1 ->2
1 2 ->2->1
2 2 ->2->2
3 2 ->2->3
3 1 ->3
1 2 ->3->1
2 2 ->3->2
3 2 ->3->3
12 rows selected
vous comparez des pommes à des oranges lorsque vous comparez la requête finale aux autres, car le NIVEAU est isolé dans celui de la table double à 1 rangée.
considérons cette requête:
select id, level as lvl
from a
connect by level <= 2
order by id, level
ce que cela veut dire, commencez par le jeu de tables (sélectionnez * From a). puis, pour chaque ligne renvoyée, connectez cette ligne à la ligne précédente. comme vous n'avez pas défini de jointure dans la connexion par, il s'agit en fait d'une jointure cartésienne, donc lorsque vous avez 3 lignes de (1,2,3) 1 jointures à 2, 1-> 3, 2-> 1, 2 -> 3, 3-> 1 et 3-> 2 et ils se rejoignent également 1-> 1,2-> 2 et 3-> 3. ces jointures sont de niveau = 2. nous avons donc 9 jointures là-bas, c'est pourquoi vous obtenez 12 lignes (3 lignes originales de "niveau 1" plus l'ensemble cartésien).
donc le nombre de lignes en sortie = rowcount + (rowcount ^ 2)
dans la dernière requête, vous isolez le niveau de cette
select level as lvl
from dual
connect by level <= 2
ce qui bien sûr renvoie 2 lignes. ceci est ensuite cartésien aux 3 lignes d'origine, donnant 6 lignes en sortie.
Vous pouvez utiliser la technique ci-dessous pour résoudre ce problème:
select id, level as lvl
from a
left outer join (select level l from dual connect by level <= 2) lev on 1 = 1
order by id