Union pour remplacer un OUTER

Union pour remplacer un OUTER - SQL/NoSQL - Programmation

Marsh Posté le 10-06-2006 à 15:32:32    

Bonjour à tous,
J'ai la requête suivante :
 

Code :
  1. SELECT X.NOM, X.PRENOMS, COUNT(*) AS NB
  2. FROM R1 X, R2 Y
  3. WHERE Y.ID (+) = X.ID
  4. GROUP BY X.NOM, X.PRENOMS
  5. ORDER BY NB DESC, X.NOM, X.PRENOMS;


 
qui devrait permettre de compter le nombre de jointures possibles entre les deux relations via l'attribut ID. Cependant les éléments ne possédant aucune jointure sont tout de même évalués à 1 au lieu de 0, il me faudrait donc effectuer une union équivalente à l'OUTER (étant sous Oracle 10g, le OUTER est représenté par (+)).
Or je n'ai aucune idée d'à quoi doit ressembler cette union. Quelqu'un pourrait-il m'éclairer ?
 
(PS : si la requête présentée si dessus est optimisable, vous pouvez me l'indiquer :hello:)
 
(PPS : existe-t-il un système pour générer de la documentation comme Doxygen pour SQL ?)


Message édité par Ynnead le 10-06-2006 à 17:55:09
Reply

Marsh Posté le 10-06-2006 à 15:32:32   

Reply

Marsh Posté le 10-06-2006 à 18:44:39    

Désolé, la question n'est pas très claire. Je ne vois pas bien le but, et ce que vient faire cette table R2. A quoi correspond l'ID ? Apparemment, il y a moins d'ID dans la table R2 que dans la table R1, est-ce bien cela ?
 
L'UNION en SQL est souvent malcomprise. Elle n'a rien à voir avec une jointure. L'UNION ne fait qu'ajouter les lignes d'une requête aux ligne d'une autre requête. Mais peut-être ce n'est pas d'une UNION SQL dont il est question ici.
 
Oui, le (+) est l'équivalent d'un OUTER JOIN, et est même plus facile utiliser à mon humble avis.
 
Je ne connais pas d'équivalent de doxigen pour SQL, qui est déjà supposé être facile à lire.
 
Que veut dire "évalué à 1" ? Si cela veut dire le count renvoie 1 au lieu de zéro, cela me parait normal à cause de la laison externe. Pour avoir un count à zéro, il faut construire la requêtre autrement. Il faudrait un petit exemple avec quelques lignes de chaque table et quelques lignes du résultat attendu pour que le but à atteindre soit plus clair.

Reply

Marsh Posté le 10-06-2006 à 19:32:26    

Tout d'abord, merci pour ta réponse :)
 
Voici le schéma des deux relations :

Code :
  1. Relation R1
  2. Name                                      Null?                 Type
  3. ----------------------------------------- -------- ----------------
  4. NOM                                      NOT NULL        VARCHAR2(25)
  5. PRENOMS                                NOT NULL        VARCHAR2(15)
  6. ID                                          NOT NULL        NUMBER(8)
  7. Relation R2
  8. Name                                      Null?               Type
  9. ----------------------------------------- -------- ----------------
  10. ID_STAGE                                  NOT NULL         NUMBER(8)
  11. ID                                             NOT NULL       NUMBER(8)


Pour chaque nuplet de R1, on doit compter le nombre de fois où R1.ID = R2.ID.
 
Voici un exemple :

Code :
  1. SQL> select * from R2;
  2. ID_STAGE    ID                                                           
  3. --------- ---------                                                           
  4.         1         8                                                           
  5.         3         8                                                           
  6.         4         9                                                           
  7.         5         1                                                           
  8.         5         8                                                           
  9.         7         1                                                           
  10.         7         4                                                           
  11. 7 rows selected.
  12. SQL> select * from R1;
  13.    ID      NOM                       PRENOMS                                   
  14. --------- ------------------------- ---------------                           
  15.         6    Nom1                        Prenom1
  16.         8    Nom2                        Prenom2                                     
  17.         1    Nom3                        Prenom3
  18.         9    Nom4                        Prenom4a                           
  19.         4    Nom4                        Prenom4b


 
Et le résultat que j'obtiens actuellement :
 

Code :
  1. NOM                       PRENOMS         NB                         
  2. ------------------------- --------------- -----------                         
  3. Nom2                       Prenom2                  3                         
  4. Nom3                       Prenom3                  2                         
  5. Nom4                       Prenom4b                 1                         
  6. Nom4                       Prenom4a                 1 
  7. Nom1                       Prenom1                   1


 
Et celui que je voudrais obtenir :) :

Code :
  1. NOM                       PRENOMS         NB                         
  2. ------------------------- --------------- -----------                         
  3. Nom2                       Prenom2                3                         
  4. Nom3                       Prenom3                2                         
  5. Nom4                       Prenom4b               1                         
  6. Nom4                       Prenom4a               1 
  7. Nom1                       Prenom1                 0


 
Merci pour ton aide :hello:


Message édité par Ynnead le 10-06-2006 à 19:40:23
Reply

Marsh Posté le 11-06-2006 à 10:16:42    

Une façon, entre autres, de le faire :
 

Code :
  1. SELECT X.NOM, X.PRENOMS, SUM(DECODE(Y.ID, NULL, 0, 1)) AS NB
  2. FROM R1 X, R2 Y
  3. WHERE Y.ID (+) = X.ID
  4. GROUP BY X.NOM, X.PRENOMS
  5. ORDER BY NB DESC, X.NOM, X.PRENOMS;

Reply

Marsh Posté le 11-06-2006 à 12:08:32    

Merci pour ta proposition, mais je ne connais pas la fonction DECODE...
Avec l'union ça donnerait quoi ?


Message édité par Ynnead le 11-06-2006 à 12:10:10
Reply

Marsh Posté le 11-06-2006 à 12:37:30    

DECODE c'est une fonction Oracle qui fait :
 
DECODE(a, b1, c1, b2, c2, ..., d)
équivaut à :
si a = b1, alors renvoie c1,
si a = b2, alors renvoie c2,
...,
sinon renvoie d.
 
On peut le faire avec un CASE également :
 
CASE Y.ID IS NULL THEN 0 ELSE 1 END CASE
 
edit : avec UNION, on peut faire ça par exemple :
 

Code :
  1. SELECT X.NOM, X.PRENOMS, COUNT(*) AS NB
  2. FROM R1 X, R2 Y
  3. WHERE Y.ID = X.ID
  4. GROUP BY X.NOM, X.PRENOMS
  5. UNION ALL
  6. SELECT X.NOM, X.PRENOMS, 0 AS NB
  7. FROM R1
  8. WHERE NOT EXISTS
  9. (SELECT 1 FROM R2 Y WHERE Y.ID = X.ID)
  10. ORDER BY NB DESC, X.NOM, X.PRENOMS;


 
mais ça revient à faire une union + une jointure externe (car le NOT EXISTS c'est grosso modo une jointure externe).


Message édité par Beegee le 11-06-2006 à 12:56:21
Reply

Marsh Posté le 11-06-2006 à 13:27:42    

Merci !
 
Néanmoins il y a une erreur dans la requête :
 
ERROR at line 6:
ORA-00904: "X"."PRENOMS": invalid identifier
 
Je modifie donc la ligne 7 comme suit :
 
FROM R1 X
 
Mais j'ai à présent une erreur sur la ligne du ORDER BY que je ne sait pas résoudre :
 
ERROR at line 10:
ORA-00904: "X"."PRENOMS": invalid identifier
 
Que faire ?

Reply

Marsh Posté le 11-06-2006 à 13:33:17    

SELECT X.NOM, X.PRENOMS, COUNT(*) AS NB
FROM R1 X, R2 Y
WHERE Y.ID = X.ID
GROUP BY X.NOM, X.PRENOMS
UNION ALL
SELECT X.NOM, X.PRENOMS, 0 AS NB
FROM R1 X
WHERE NOT EXISTS
(SELECT 1 FROM R2 Y WHERE Y.ID = X.ID)
ORDER BY NB DESC, NOM, PRENOMS;
 
Cependant je ne sais plus si Oracle interprète correctement l'ORDER BY, ou s'il faut mettre le résultat de l'union dans une sous-requête pour que l'ORDER BY s'applique correctement ...
 
Mais c'est bien plus simple avec le DECODE ;)

Reply

Marsh Posté le 11-06-2006 à 14:03:29    

Ça fonctionne parfaitement !
 
Je me doute bien que le DECODE est plus efficace, mais je préfère utiliser l'UNION dans ce cas. Merci encore :)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed