|
Publicité | ||||||||||||||||||||||
|
|
#1 (permalink) | ||
|
Expert Confirmé
![]() Date d'inscription: mai 2004
Messages: 1 704
|
Bonjour à tous.
Je viens vers vous concernant un problème de comportement (un bug ?) dans les requêtes hierarchiques sur des données contenant des boucles. Citation:
Soit la table suivante : Code :
DROP TABLE "OBJECT_LINK"; CREATE TABLE "OBJECT_LINK" ( OBJECT VARCHAR2(10) NOT NULL -- ex: 'MYSCHEMA.MYTABLE.MYCOLUMN' ,LINKED_OBJECT VARCHAR2(10) NOT NULL -- ex: 'MYSCHEMA.MYTABLE.MYCOLUMN' ,TYPE VARCHAR2(10) NOT NULL -- ex: 'refers' ); Cas 1 Code :
A-->B ^ | | v D<--C Code :
DELETE FROM OBJECT_LINK; INSERT INTO OBJECT_LINK VALUES ('A', 'B', 'refers'); INSERT INTO OBJECT_LINK VALUES ('B', 'C', 'refers'); INSERT INTO OBJECT_LINK VALUES ('C', 'D', 'refers'); INSERT INTO OBJECT_LINK VALUES ('D', 'A', 'refers'); SELECT connect_by_root OBJECT, level, TYPE, OBJECT, LINKED_OBJECT FROM "OBJECT_LINK" connect BY OBJECT = prior LINKED_OBJECT START WITH OBJECT = 'A'; Citation:
Code :
SELECT connect_by_root OBJECT, level, OBJECT, TYPE, LINKED_OBJECT FROM "OBJECT_LINK" connect BY nocycle OBJECT = prior LINKED_OBJECT START WITH OBJECT = 'A'; Code :
CONNECT_BY LEVEL OBJECT TYPE LINKED_OBJ ---------- ---------- ---------- ---------- ---------- A 1 A refers B A 2 B refers C A 3 C refers D A 4 D refers A Cas 2 Code :
A-->B-->E ^ | | | v v D<--C<--F Code :
DELETE FROM OBJECT_LINK; INSERT INTO OBJECT_LINK VALUES ('A', 'B', 'refers'); INSERT INTO OBJECT_LINK VALUES ('B', 'C', 'refers'); INSERT INTO OBJECT_LINK VALUES ('C', 'D', 'refers'); INSERT INTO OBJECT_LINK VALUES ('D', 'A', 'refers'); INSERT INTO OBJECT_LINK VALUES ('B', 'E', 'refers'); INSERT INTO OBJECT_LINK VALUES ('E', 'F', 'refers'); INSERT INTO OBJECT_LINK VALUES ('F', 'C', 'refers'); SELECT connect_by_root OBJECT, level, OBJECT, TYPE, LINKED_OBJECT FROM "OBJECT_LINK" connect BY nocycle OBJECT = prior LINKED_OBJECT START WITH OBJECT = 'A'; Code :
CONNECT_BY LEVEL OBJECT TYPE LINKED_OBJ ---------- ---------- ---------- ---------- ---------- A 1 A refers B A 2 B refers C A 3 C refers D A 4 D refers A A 2 B refers E A 3 E refers F A 4 F refers C A 5 C refers D A 6 D refers A 3 C refers D 5 C refers D 4 D refers A 6 D refers A Ces "doublons" s'expliquent par le fait qu'ils n'ont pas lieu dans le même chemin. Le chemin a donc de l'importance. Si on présente la requête en arbre cela se comprend : Code :
SELECT lpad(' ', level-1) || level ||' '|| OBJECT ||' '|| TYPE ||' '|| LINKED_OBJECT FROM "OBJECT_LINK" connect BY nocycle OBJECT = prior LINKED_OBJECT START WITH OBJECT = 'A'; Code :
1 A refers B 2 B refers C 3 C refers D 4 D refers A 2 B refers E 3 E refers F 4 F refers C 5 C refers D 6 D refers A Cas 3 Code :
A-->C<--D-->F-->L | | ^ | ^ v v | v | B H-->I J-->K | | | v v v E G M Code :
DELETE FROM OBJECT_LINK; INSERT INTO OBJECT_LINK VALUES ('A', 'C', 'refers'); INSERT INTO OBJECT_LINK VALUES ('A', 'B', 'refers'); INSERT INTO OBJECT_LINK VALUES ('B', 'E', 'refers'); INSERT INTO OBJECT_LINK VALUES ('C', 'H', 'refers'); INSERT INTO OBJECT_LINK VALUES ('H', 'I', 'refers'); INSERT INTO OBJECT_LINK VALUES ('I', 'D', 'refers'); INSERT INTO OBJECT_LINK VALUES ('D', 'F', 'refers'); INSERT INTO OBJECT_LINK VALUES ('D', 'C', 'refers'); INSERT INTO OBJECT_LINK VALUES ('F', 'J', 'refers'); INSERT INTO OBJECT_LINK VALUES ('J', 'K', 'refers'); INSERT INTO OBJECT_LINK VALUES ('J', 'G', 'refers'); INSERT INTO OBJECT_LINK VALUES ('K', 'L', 'refers'); INSERT INTO OBJECT_LINK VALUES ('F', 'L', 'refers'); INSERT INTO OBJECT_LINK VALUES ('K', 'M', 'refers'); SELECT connect_by_root OBJECT, level, OBJECT, TYPE, LINKED_OBJECT FROM "OBJECT_LINK" connect BY nocycle OBJECT = prior LINKED_OBJECT START WITH OBJECT = 'A'; Code :
CONNECT_BY LEVEL OBJECT TYPE LINKED_OBJ ---------- ---------- ---------- ---------- ---------- A 1 A refers C A 2 C refers H A 3 H refers I A 4 I refers D A 5 D refers F A 6 F refers J A 7 J refers K A 8 K refers L A 8 K refers M A 7 J refers G A 6 F refers L A 1 A refers B A 2 B refers E Ceci prouve que la gestion des boucles avec une requête hierarchique n'est pas du tout au point, même en 10g puisqu'on peut perdre des relations (alors que la plupart des cas sont correctement gérés). En conclusion, si je ne trouve pas une méthode pour contourner ce comportement je vais être obligé d'abandonner les requêtes hierarchiques pour faire ma récursivité en code applicatif (toujours pratique quand on utilise un ETL ou un outil de requêtage). Donc si quelqu'un s'est déjà frotté à ce problème, a du temps pour m'aider ou a ses entrées chez Oracle, merci du coup de main.
__________________
Il vaut mieux monopoliser son intelligence sur des bêtises que sa bêtise sur des choses intelligentes. Mon combat pour les droits des consommateurs face aux abus des grandes marques. |
||
|
|
|
|
|
#3 (permalink) |
|
Expert Confirmé Sénior
![]() ![]() ![]() Date d'inscription: décembre 2005
Localisation: Suisse
Messages: 2 590
|
je suis assez d'accord que D refere C est manquant. A mon sens ça vaut le coup d'ouvrir un bug sur Metalink.
Quant à l'implémentation propre au chemin, c'est bien ça le bug qui fait que CONNECT BY LEVEL<10 fonctionne (à tort ). J'ai ouvert une SR à ce sujet il y a fort longtemps ;-)
|
|
|
|
|
|
#4 (permalink) |
|
Expert Confirmé
![]() Date d'inscription: mai 2004
Messages: 1 704
|
Salut Laurent. C'est quoi cette histoire de LEVEL < 10 ? Tu peux développer stp ?
Merci
__________________
Il vaut mieux monopoliser son intelligence sur des bêtises que sa bêtise sur des choses intelligentes. Mon combat pour les droits des consommateurs face aux abus des grandes marques. |
|
|
|
|
|
#6 (permalink) |
|
Expert Confirmé Sénior
![]() Date d'inscription: septembre 2008
Localisation: Paris
Âge: 32
Messages: 2 631
|
Pour votre soucis, je ne sais pas si c'est viable dans votre cas pratique mais si vous pouvez vous passez des informations level et connect_by_root vous pouvez obtenir tous les résultats ainsi :
Code :
SELECT DISTINCT OBJECT, TYPE, LINKED_OBJECT FROM OBJECT_LINK connect BY nocycle OBJECT = prior LINKED_OBJECT START WITH OBJECT IN (SELECT object FROM OBJECT_LINK GROUP BY object HAVING count(*) > 1) |
|
|
|
|
#7 (permalink) |
|
Expert Confirmé
![]() Date d'inscription: mai 2004
Messages: 1 704
|
Hmmm disons que cette méthode va me permettre d'avoir toutes les relations, mais pas toutes les relations en partant d'un point donné.
J'utilise déjà cette méthode pour "mettre à plat" toutes mes relations à partir de tous les objets possibles, mais je perds toujours des relations dans certains cas de boucles. PS : ok je connaissais pas l'astuce du DUAL connect by
__________________
Il vaut mieux monopoliser son intelligence sur des bêtises que sa bêtise sur des choses intelligentes. Mon combat pour les droits des consommateurs face aux abus des grandes marques. |
|
|
|
|
|
#8 (permalink) |
|
Expert Confirmé Sénior
![]() ![]() ![]() Date d'inscription: décembre 2005
Localisation: Suisse
Messages: 2 590
|
Et bien tant mieux
![]() Cette astuce est une perversion du système de hiérarchie et elle a l'avantage et l'inconvénient d'être performante. Mais ce n'est pas une syntaxe légale. En fait, il y a boucle dès que la valeur courante existe dans la liste des "PRIOR" précédentes. Cependant si tu fais CONNECT BY 1=1, tu as une boucle infinie, mais comme tu n'as pas de PRIOR, la boucle n'est pas détectée. Différentes astuces plus ou moins réussies ont permis d'abuser cette technique pour créer des lignes. Il y a bien sûr plein de bugs et ce n'est pas supporté à mon humble avis. Pour revenir à la relation manquante, je vais tenter de faire ouvrir un bug sur Metalink. A+ Laurent PS: bien sûr j'update dès que j'ai le numéro du bug... |
|
|
|
|
|
#9 (permalink) |
|
Expert Confirmé Sénior
![]() ![]() ![]() Date d'inscription: décembre 2005
Localisation: Suisse
Messages: 2 590
|
j'ai ajouté and prior sys_guid() is not null dans la clause connect by, suite à un commentaire sur mon blog.
Code :
SELECT connect_by_root OBJECT, level, OBJECT, TYPE, LINKED_OBJECT FROM "OBJECT_LINK" connect BY nocycle OBJECT = prior LINKED_OBJECT AND prior sys_guid() IS NOT NULL START WITH OBJECT = 'A'; Code :
CONNECT_BY LEVEL OBJECT TYPE LINKED_OBJ ---------- ---------- ---------- ---------- ---------- A 1 A refers B A 2 B refers E A 1 A refers C A 2 C refers H A 3 H refers I A 4 I refers D A 5 D refers C ====> BINGO A 5 D refers F A 6 F refers J A 7 J refers G A 7 J refers K A 8 K refers L A 8 K refers M A 6 F refers L |
|
|
|
|
|
#10 (permalink) |
|
Expert Confirmé Sénior
![]() ![]() ![]() Date d'inscription: décembre 2005
Localisation: Suisse
Messages: 2 590
|
mais c'est probablement une mauvaise idée, Oracle risque de boucler infiniment dans certains cas
Code :
WITH t AS (SELECT 1 x, 2 y FROM DUAL UNION ALL SELECT 2, 2 FROM DUAL) SELECT * FROM t CONNECT BY NOCYCLE x = PRIOR y AND PRIOR SYS_GUID () IS NOT NULL START WITH x = 1; Code :
X Y - - 1 2 2 2 2 2 2 2 2 2 2 2 ... |
|
|
|
|
|
#11 (permalink) |
|
Expert Confirmé Sénior
![]() ![]() ![]() Date d'inscription: décembre 2005
Localisation: Suisse
Messages: 2 590
|
peut-être que
Code :
CONNECT BY NOCYCLE OBJECT = PRIOR linked_object AND OBJECT != PRIOR object
|
|
|
|
|
|
![]() |
||
[10g] Bug connect by nocycle - Requete hierarchique
|
||
| Outils de la discussion | |
|
|