2009-05-21 7 views
2

J'ai une requête hiérarchique pour suivre une structure de rapport. Cela fonctionne presque, sauf que cela ne rapporte pas le nœud de très haut niveau, probablement parce que les personnes de haut niveau se «rapportent» à elles-mêmes.Oracle Requête hiérarchique: comment inclure le parent de premier niveau

La requête est:

select 
    level, 
    empid, 
    parentid 
from usertable 
connect by nocycle prior parentid= empid 
start with empid = 50 

Ce produit:

LEVEL EMPID PARENTID    
------ ----- -------- 
1  50 258    
2  258 9555 
3  9555 17839 

Je ne reçois pas un niveau 4, car il ressemblerait à ceci:

4  17839 17839 

Sans modifier les données , existe-t-il un moyen de modifier ma requête pour que les 4 niveaux soient retournés? Le but est d'obtenir les empids, donc je peux faire un chèque de

id in (hierarchical subquery)

BTW, si je retire la nocycle de la requête que je reçois une erreur.

Répondre

5

Chris,

Vous obtenez seulement 3 rangs parce que votre ligne de haut niveau est pas défini comme il se doit pour traiter les requêtes hiérarchiques. Généralement, la ligne de niveau supérieur, ou le président KING dans la table EMP bien connue d'Oracle, n'a pas de gestionnaire. Dans votre cas, vous ne devez pas définir le parentid de 17389 à 17389 lui-même, mais à NULL. Mettez à jour la table en conséquence, ou utilisez une vue pour s'adapter à cette situation.

Un exemple:

SQL> select empno 
    2  , mgr 
    3 from emp 
    4 where empno in (7876,7788,7566,7839) 
    5/

    EMPNO  MGR 
---------- ---------- 
     7566  7839 
     7788  7566 
     7839  7839 
     7876  7788 

4 rijen zijn geselecteerd. 

Cette partie de la table EMP a quatre niveaux avec sa ligne de premier niveau (7839) fixé à lui-même. La même chose que votre empid 17839. Et cela conduit à trois lignes à l'aide de votre requête:

SQL> select level 
    2  , empno 
    3  , mgr 
    4  from emp 
    5 connect by nocycle prior mgr = empno 
    6 start with empno = 7876 
    7/

    LEVEL  EMPNO  MGR 
---------- ---------- ---------- 
     1  7876  7788 
     2  7788  7566 
     3  7566  7839 

3 rijen zijn geselecteerd. 

Soit utiliser un (en ligne) en vue de définir la colonne mgr/parentid null pour le niveau supérieur:

SQL> select level 
    2  , empno 
    3  , mgr 
    4  from (select empno 
    5     , nullif(mgr,empno) mgr 
    6    from emp 
    7   ) 
    8 connect by nocycle prior mgr = empno 
    9 start with empno = 7876 
10/

    LEVEL  EMPNO  MGR 
---------- ---------- ---------- 
     1  7876  7788 
     2  7788  7566 
     3  7566  7839 
     4  7839 

4 rijen zijn geselecteerd. 

Ou fixer vos données avec une instruction UPDATE:

SQL> update emp 
    2  set mgr = null 
    3 where empno = 7839 
    4/

1 rij is bijgewerkt. 

SQL> select level 
    2  , empno 
    3  , mgr 
    4  from emp 
    5 connect by nocycle prior mgr = empno 
    6 start with empno = 7876 
    7/

    LEVEL  EMPNO  MGR 
---------- ---------- ---------- 
     1  7876  7788 
     2  7788  7566 
     3  7566  7839 
     4  7839 

4 rijen zijn geselecteerd. 

Et vous pouvez laisser le mot-clé NOCYCLE aussi bien, après avoir terminé la fixation.

Cordialement, Rob.

3

Vous devez faire la hiérarchie dans l'autre sens, de la racine aux feuilles.

select 
    level, 
    empid, 
    parentid 
from usertable 
start with empid = 17839 
connect by empid != 17839 and prior empid = parentid 

LEVEL     EMPID     PARENTID    
---------------------- ---------------------- ---------------------- 
1      17839     17839     
2      9555     17839     
3      258     9555     
4      50      258      

4 rows selected 
+0

Malheureusement, ça ne va pas fonctionner. Le niveau supérieur aura un tas de niveau 2, mais je veux seulement le niveau 2 dans la hiérarchie au-dessus du niveau 4. Pensez employé, gestionnaire, directeur, VP-directeur et VP peut voir les données créées par un employé, mais un autre directeur qui rend compte à ce directeur ne peut pas. – chris

0

semble avoir un cycle dans les données. Sans "nocycle" ça ne marchera pas tout de suite. Si vous savez que toutes vos données ont un niveau d'imbrication maximum de 4, alors vous pouvez ajouter la condition "et le niveau < = 4" et retirer nocycle. Devrait marcher.

+0

Le niveau d'imbrication varie, malheureusement. – chris

1

Vous n'avez pas besoin de changer de structure.

il suffit d'utiliser la requête suivante

select 
    level, 
    empid, 
    parentid 
from usertable 
connect by prior parentid = empid 
     AND parentid <> empid -- This line prohibits cycling and ALLOWS a row where parentid = empid 
start with empid = 50 
0

réponse de Van Heddegem Roeland ne fonctionne pas pour moi, je l'avais déjà essayé, mais j'ai réussi à le faire sans une vue en ligne, dans la clause de connexion, en ajoutant: -

and prior empid <> parentid 

Le message suivant explique pourquoi cela fonctionne - si vous pouvez vous en passer la tête! Bien que cela fasse du sens logique, une fois que vous l'avez «compris». (Il est à voir avec l'ordre d'évaluation de chaque côté de l'opérateur <>.)

Oracle: Connect By Loop in user data

La vue en ligne fonctionne, mais sans la recherche sur votre ensemble de données particulier, je ne sais pas quel impact une ligne vue peut avoir sur le chemin de la requête. Ajoutant la clause supplémentaire est probablement la «bonne» façon de le faire dans la plupart des situations, à mon humble avis.

Questions connexes