IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SQL Oracle Discussion :

[10g] Bug connect by nocycle - Requete hierarchique


Sujet :

SQL Oracle

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert Avatar de nuke_y
    Profil pro
    Indépendant en analyse de données
    Inscrit en
    Mai 2004
    Messages
    2 076
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Indépendant en analyse de données

    Informations forums :
    Inscription : Mai 2004
    Messages : 2 076
    Par défaut [10g] Bug connect by nocycle - Requete hierarchique
    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.

    Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
    With the Partitioning, OLAP and Data Mining options

    Soit la table suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A-->B
    ^   |
    |   v
    D<--C
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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';
    On obtient une erreur car il y a une boucle dans les données :
    ERROR:
    ORA-01436: boucle CONNECT BY dans les données utilisateur
    Il faut utiliser le mot clé "nocycle" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    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
    Les 4 références sont bien données. Parfait


    Cas 2

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A-->B-->E
    ^   |   |
    |   v   v
    D<--C<--F
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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
    Les 4 references sont bien données mais il y a 2 doublons ce qui prouve qu'Oracle ne s'arrête pas dès qu'il commence la boucle :
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    select  lpad(' ', level-1) || level ||' '|| OBJECT ||' '|| TYPE ||' '|| LINKED_OBJECT
    from "OBJECT_LINK"
    connect by nocycle OBJECT = prior LINKED_OBJECT
    START WITH OBJECT = 'A';
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    A-->C<--D-->F-->L
    |   |   ^   |   ^
    v   v   |   v   |
    B   H-->I   J-->K
    |           |   |
    v           v   v
    E           G   M
    cf ici

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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
    On a perdu D refers C

    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.

  2. #2
    Membre chevronné

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    507
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 507
    Par défaut
    Sujet très intéressant.

  3. #3
    Expert confirmé
    Avatar de laurentschneider
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Décembre 2005
    Messages
    2 944
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Finance

    Informations forums :
    Inscription : Décembre 2005
    Messages : 2 944
    Par défaut
    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. #4
    Membre Expert Avatar de nuke_y
    Profil pro
    Indépendant en analyse de données
    Inscrit en
    Mai 2004
    Messages
    2 076
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Indépendant en analyse de données

    Informations forums :
    Inscription : Mai 2004
    Messages : 2 076
    Par défaut
    Salut Laurent. C'est quoi cette histoire de LEVEL < 10 ? Tu peux développer stp ?

    Merci

  5. #5
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 454
    Par défaut
    C'est l'astuce pour générer n lignes à la volée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    select level from dual
    connect by level <= 10
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    LEVEL
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

  6. #6
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 454
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 454
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    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)

Discussions similaires

  1. [forms 10g] BUG avec SET_BLOCK_PROPERTY ?
    Par Magnus dans le forum Forms
    Réponses: 7
    Dernier message: 22/03/2007, 16h15
  2. [10g][PL/SQL] exécuter la requete d'une fonction
    Par gojira dans le forum Oracle
    Réponses: 4
    Dernier message: 31/10/2006, 11h46
  3. [Oracle 10g] Question sur les sous-requetes
    Par hotkebab99 dans le forum Oracle
    Réponses: 2
    Dernier message: 27/10/2006, 11h25
  4. Réponses: 2
    Dernier message: 14/06/2006, 08h53
  5. [oracle 10g] aide connection sql
    Par isidore dans le forum Oracle
    Réponses: 8
    Dernier message: 15/02/2006, 11h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo