Précédent   Forum des professionnels en informatique > Bases de données > Oracle > SQL
SQL Forum d'entraide sur le SQL pour Oracle
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 19/04/2011, 19h51   #1
Membre régulier
 
Inscription : mars 2007
Messages : 78
Détails du profil
Informations personnelles :
Âge : 33
Localisation : Suisse

Informations forums :
Inscription : mars 2007
Messages : 78
Points : 75
Points : 75
Par défaut [SQL] 1 Branche avec CONNECT BY

Bonsoir,

Est-ce avec une requête connect by et start with.
On peut obtenir qu'une "branche" d'un arbre.

c'est à dire je voudrais voir apparaître que la partie rouge des données
ci-dessous
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  level |  employee     | empno | manager
------- +-------------     +-------+---------
     1   | KING              |  7839 |
     2   |    JONES         |  7566 |    7839
     3   |       SCOTT      |  7788 |    7566
     4   |          ADAMS  |  7876 |    7788
     3   |       FORD       |  7902 |    7566
     4   |          SMITH   |  7369 |    7902
     2   |    BLAKE         |  7698 |    7839
     3   |       ALLEN      |  7499 |    7698
     3   |       WARD      |  7521 |    7698
     3   |       MARTIN    |  7654 |    7698
     3   |       TURNER   |  7844 |    7698
     3   |       JAMES      |  7900 |    7698
     2   |    CLARK         |  7782 |    7839
     3   |       MILLER     |  7934 |    7782
Or a moins de passer par un union
qui me sortira le level 1 puis l'autre partie de la branche "blake"

je ne vois pas comment....

Si il y a une solution sans union je suis preneur

Merci
alx13 est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 20/04/2011, 01h08   #2
Rédacteur
 
Inscription : décembre 2002
Messages : 2 385
Détails du profil
Informations personnelles :
Localisation : France, Var (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : décembre 2002
Messages : 2 385
Points : 3 261
Points : 3 261
Pour le cas précis, vous pouvez utiliser ceci :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
col nom format A30
SELECT lpad('-', (level-1)*3, '-') || ename nom
FROM emp
start WITH ename='KING'
connect BY prior empno=mgr
AND (prior ename='BLAKE' OR ename='BLAKE');
 
NOM
------------------------------
KING
---BLAKE
------ALLEN
------WARD
------MARTIN
------TURNER
------JAMES
Mais ça ne marche que parce que BLAKE n'a pas de "petits enfants".

Dans un cas plus général, par exemple tous les descendants de JONES, il faut trouver un critère respecté par tous les descendants.
On peut jouer sur SYS_CONNECT_BY_PATH :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SELECT lpad('-', level-1, '-') || ename ename, sys_connect_by_path(ename, '-') chaine
FROM emp
start WITH mgr IS NULL
connect BY prior empno=mgr;
 
ENAME                          CHAINE
------------------------------ ----------------------------------------
KING                           -KING
-JONES                         -KING-JONES
--SCOTT                        -KING-JONES-SCOTT
---ADAMS                       -KING-JONES-SCOTT-ADAMS
--FORD                         -KING-JONES-FORD
---SMITH                       -KING-JONES-FORD-SMITH
-BLAKE                         -KING-BLAKE
--ALLEN                        -KING-BLAKE-ALLEN
--WARD                         -KING-BLAKE-WARD
--MARTIN                       -KING-BLAKE-MARTIN
--TURNER                       -KING-BLAKE-TURNER
--JAMES                        -KING-BLAKE-JAMES
-CLARK                         -KING-CLARK
--MILLER                       -KING-CLARK-MILLER
Malheureusement cette fonction n'est pas utilisable dans un WHERE, donc il faut passer par une sous-requête.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
col ename format A30
col chaine format A40
SELECT ename, empno, mgr FROM
   (SELECT lpad('-', (level-1)*3, '-') || ename ename, empno, mgr, sys_connect_by_path(ename, '-') chaine
   FROM emp
   start WITH mgr IS NULL
   connect BY prior empno=mgr)
WHERE chaine='-KING'
   OR chaine LIKE '-KING-JONES%';
 
ENAME                               EMPNO        MGR
------------------------------ ---------- ----------
KING                                 7839
---JONES                             7566       7839
------SCOTT                          7788       7566
---------ADAMS                       7876       7788
------FORD                           7902       7566
---------SMITH                       7369       7902
Si vous ne voulez garder qu'une seule branche, cette solution n'est évidemment pas plus légère que l'union, mais si vous devez garder plusieurs branches, il suffira d'ajouter les conditions OR correspondantes.
__________________
Consultant / formateur Oracle indépendant
Certifié OCP 10g et 11g, sécurité 11g
Pomalaix est déconnecté   Envoyer un message privé Réponse avec citation 01
Vieux 20/04/2011, 08h36   #3
Membre régulier
 
Inscription : mars 2007
Messages : 78
Détails du profil
Informations personnelles :
Âge : 33
Localisation : Suisse

Informations forums :
Inscription : mars 2007
Messages : 78
Points : 75
Points : 75
Merci Pomalaix,

ça me plaît bien comme solution, je vais essayer de ce pas.
alx13 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/04/2011, 13h32   #4
Membre régulier
 
Inscription : mars 2007
Messages : 78
Détails du profil
Informations personnelles :
Âge : 33
Localisation : Suisse

Informations forums :
Inscription : mars 2007
Messages : 78
Points : 75
Points : 75
ça marche bien

Merci encore
alx13 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/04/2011, 18h32   #5
Expert Confirmé Sénior


 
Avatar de laurentschneider
 
Homme Laurent Schneider
Administrateur de base de données
Inscription : décembre 2005
Messages : 2 925
Détails du profil
Informations personnelles :
Nom : Homme Laurent Schneider
Localisation : Suisse

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

Informations forums :
Inscription : décembre 2005
Messages : 2 925
Points : 4 547
Points : 4 547
Citation:
Envoyé par alx13 Voir le message
ça marche bien
Tu m'en diras tant

Attendu que la hiérarchie est bâtie au fur et à mesure, au moment où l'on accède à un ancêtre de BLAKE, on ne peut pas encore savoir qu'il s'agisse d'un ancêtre de BLAKE. Il faut donc une sous-requête, je serais curieux de voir une soluce avec seulement une union... et qui bien sûre prévoit les arrières-arrières-arrières-grand-pères et arrières-arrières-arrières-petits-enfants

Je suis sûr qu'il y a mieux, mais voici un exemple avec un CTE récursif et un IN (subquery).

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
WITH e (l, empno, ename, mgr, child) AS (
SELECT 1,empno,ename,mgr,CASE WHEN ename = 'BLAKE' THEN 1 END
FROM emp WHERE mgr IS NULL
UNION ALL
SELECT e.l + 1, f.empno, f.ename, f.mgr,
  CASE WHEN f.ename != 'BLAKE' THEN e.child ELSE 1 END
FROM emp f, e WHERE e.empno = f.mgr)
SEARCH DEPTH FIRST BY ename SET ord,
m (empno, mgr) AS (
SELECT empno, mgr FROM emp WHERE ename = 'BLAKE'
UNION ALL
SELECT f.empno, f.mgr FROM emp f, m WHERE m.mgr = f.empno)
SELECT l,lpad(' ',l*3-3)||ename,empno,mgr FROM e
WHERE child = 1 OR empno IN (SELECT mgr FROM m)
ORDER BY ord;
Code :
1
2
3
4
5
6
7
8
9
     level employee              empo    manager
---------- --------------- ---------- ----------
         1 KING                  7839           
         2    BLAKE              7698       7839
         3       ALLEN           7499       7698
         3       JAMES           7900       7698
         3       MARTIN          7654       7698
         3       TURNER          7844       7698
         3       WARD            7521       7698

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
WITH e (l, empno, ename, mgr, child) AS (
SELECT 1,empno,ename,mgr,CASE WHEN ename =  'ADAMS'THEN 1 END
FROM emp WHERE mgr IS NULL
UNION ALL
SELECT e.l + 1, f.empno, f.ename, f.mgr,
  CASE WHEN f.ename !=  'ADAMS'THEN e.child ELSE 1 END
FROM emp f, e WHERE e.empno = f.mgr)
SEARCH DEPTH FIRST BY ename SET ord,
m (empno, mgr) AS (
SELECT empno, mgr FROM emp WHERE ename =  'ADAMS'
UNION ALL
SELECT f.empno, f.mgr FROM emp f, m WHERE m.mgr = f.empno)
SELECT l,lpad(' ',l*3-3)||ename,empno,mgr FROM e
WHERE child = 1 OR empno IN (SELECT mgr FROM m)
ORDER BY ord;
Code :
1
2
3
4
5
6
     level employee              empo    manager
---------- --------------- ---------- ----------
         1 KING                  7839           
         2    JONES              7566       7839
         3       SCOTT           7788       7566
         4          ADAMS        7876       7788

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
WITH e (l, empno, ename, mgr, child) AS (
SELECT 1,empno,ename,mgr,CASE WHEN ename = 'KING' THEN 1 END
FROM emp WHERE mgr IS NULL
UNION ALL
SELECT e.l + 1, f.empno, f.ename, f.mgr,
  CASE WHEN f.ename != 'KING' THEN e.child ELSE 1 END
FROM emp f, e WHERE e.empno = f.mgr)
SEARCH DEPTH FIRST BY ename SET ord,
m (empno, mgr) AS (
SELECT empno, mgr FROM emp WHERE ename = 'KING'
UNION ALL
SELECT f.empno, f.mgr FROM emp f, m WHERE m.mgr = f.empno)
SELECT l,lpad(' ',l*3-3)||ename,empno,mgr FROM e
WHERE child = 1 OR empno IN (SELECT mgr FROM m)
ORDER BY ord;
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     level employee              empo    manager
---------- --------------- ---------- ----------
         1 KING                  7839           
         2    BLAKE              7698       7839
         3       ALLEN           7499       7698
         3       JAMES           7900       7698
         3       MARTIN          7654       7698
         3       TURNER          7844       7698
         3       WARD            7521       7698
         2    CLARK              7782       7839
         3       MILLER          7934       7782
         2    JONES              7566       7839
         3       FORD            7902       7566
         4          SMITH        7369       7902
         3       SCOTT           7788       7566
         4          ADAMS        7876       7788
__________________
Mon blog : laurentschneider.com
Mon livre : Advanced Oracle SQL Programming
laurentschneider est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/04/2011, 18h38   #6
Expert Confirmé Sénior


 
Avatar de laurentschneider
 
Homme Laurent Schneider
Administrateur de base de données
Inscription : décembre 2005
Messages : 2 925
Détails du profil
Informations personnelles :
Nom : Homme Laurent Schneider
Localisation : Suisse

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

Informations forums :
Inscription : décembre 2005
Messages : 2 925
Points : 4 547
Points : 4 547
Pour les vieilles versions

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
WITH e AS (
SELECT level l, empno,ename,mgr,sys_connect_by_path(ename,'/')||'/' p
FROM emp
start WITH mgr IS NULL
connect BY prior empno=mgr),
m AS (
SELECT mgr
FROM emp
start WITH ename='BLAKE'
connect BY empno=prior mgr)
SELECT l "level",lpad(' ',l*3-3)||ename "employee",empno "empo",mgr "manager"
FROM e
WHERE p LIKE '%/BLAKE/%' OR empno IN (SELECT mgr FROM m);
__________________
Mon blog : laurentschneider.com
Mon livre : Advanced Oracle SQL Programming
laurentschneider est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/04/2011, 23h09   #7
Rédacteur
 
Inscription : décembre 2002
Messages : 2 385
Détails du profil
Informations personnelles :
Localisation : France, Var (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : décembre 2002
Messages : 2 385
Points : 3 261
Points : 3 261
Citation:
Envoyé par laurentschneider Voir le message
Tu m'en diras tant <bla bla>
Il faudrait déjà s'assurer qu'on répond à la même question !

De la description initiale, je traduis : affiche-moi KING, BLAKE et ses subordonnés. (Et je suppose que BLAKE est relié sans intermédiaire à KING, mais l'adaptation est mineure pour se placer dans un cas plus général).

Vous vous traduisez visiblement par : affiche-moi toute la chaîne hiérarchique dans laquelle se situe BLAKE, autrement dit ses supérieurs depuis le grand chef, BLAKE lui-même et ses subordonnés.
__________________
Consultant / formateur Oracle indépendant
Certifié OCP 10g et 11g, sécurité 11g
Pomalaix est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/04/2011, 10h14   #8
Expert Confirmé Sénior


 
Avatar de laurentschneider
 
Homme Laurent Schneider
Administrateur de base de données
Inscription : décembre 2005
Messages : 2 925
Détails du profil
Informations personnelles :
Nom : Homme Laurent Schneider
Localisation : Suisse

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

Informations forums :
Inscription : décembre 2005
Messages : 2 925
Points : 4 547
Points : 4 547
On peut obtenir qu'une "branche" d'un arbre.

Il s'agit bien d'une question hiérarchique.

Bon, à la question : comment obtenir ce qu'il y a en rouge on aurait pu répondre
Code :
SELECT * FROM TABLE(sys.odcivarchar2list('KING','BLAKE','ALLEN','WARD','MARTIN','TURNER','JAMES'))
__________________
Mon blog : laurentschneider.com
Mon livre : Advanced Oracle SQL Programming
laurentschneider est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/04/2011, 11h47   #9
Rédacteur
 
Inscription : décembre 2002
Messages : 2 385
Détails du profil
Informations personnelles :
Localisation : France, Var (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : décembre 2002
Messages : 2 385
Points : 3 261
Points : 3 261
Citation:
Envoyé par laurentschneider Voir le message
Bon, à la question : comment obtenir ce qu'il y a en rouge on aurait pu répondre
Code :
SELECT * FROM TABLE(sys.odcivarchar2list('KING','BLAKE','ALLEN','WARD','MARTIN','TURNER','JAMES'))
Mouarf !

Il ne reste plus qu'à attendre que le demandeur repasse pour nous expliquer ce qu'il voulait réellement.
__________________
Consultant / formateur Oracle indépendant
Certifié OCP 10g et 11g, sécurité 11g
Pomalaix est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 10h08.


 
 
 
 
Partenaires

Hébergement Web