Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2867 connectés 

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Requête externe sur résultat de requête externe

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Requête externe sur résultat de requête externe

n°1787767
Ju -
Posté le 16-09-2008 à 17:26:35  profilanswer
 

Salut à tous,
Je fais face (courageusement) au problème de construction de requête suivant. Je n'ai rien trouvé sur le faux-rhum qui pourrait m'aiguiller alors toute aide à ce sujet sera appréciée à sa juste valeur!
 
J'ai 3 tables A, B, C:
A contient des identifiants, C des données, B est une table d'association de A vers C.
J'ai donc une structure qui ressemble à:
 
A
ID=1
ID=2
ID=3
 
B
ID=1  NUM=4
ID=2  NUM=5
ID=2  NUM=6
ID=3  NUM=4
 
C
NUM=4  VAL=7
NUM=5  VAL=8
 
Mon but est de récupérer les données VAL de C relatives au ID 2 de A qui ont un C.VAL=8 (!)  
Je voudrais donc récupérer cette unique ligne:


ID  VAL
2   8


J'écris donc quelque chose comme ça (je veux éviter autant que possible l'utilisation de sous-requêtes pour des raisons de perfs):

Code :
  1. SELECT a.ID, c.VAL
  2. FROM A a, B b, C c
  3. WHERE a.ID = 2
  4. AND a.ID = b.ID(+)
  5. AND b.NUM = c.NUM(+)
  6. AND c.VAL(+) = 8


Pourtant, je récupère 4 résultats, soit 2^2 lignes.
Je comprends qu'Oracle effectue la 2nde jointure externe sans tenir compte du résultat de la 3e... mais comment faire autrement?

mood
Publicité
Posté le 16-09-2008 à 17:26:35  profilanswer
 

n°1787769
MagicBuzz
Posté le 16-09-2008 à 17:29:10  profilanswer
 

pourquoi tu fais une jointure ouverte ? (parceque pour le résultat que tu veux, tu n'en a pas besoin)
 
et si tu as une version >= 9i, alors écrit ta requête avec la syntaxe SQL92, à savoir en utilisant les jointures de type "right outer join", qui est à la fois plus explicite pour toi et pour oracle. si je comprends bien éventuellement ton problème, je pense d'ailleurs que la réponse se trouve dans cette syntaxe. la jointure entre b et c est un inner join et non un outer join

Message cité 1 fois
Message édité par MagicBuzz le 16-09-2008 à 17:30:04
n°1787798
Ju -
Posté le 16-09-2008 à 19:08:42  profilanswer
 

MagicBuzz a écrit :

pourquoi tu fais une jointure ouverte ? (parceque pour le résultat que tu veux, tu n'en a pas besoin)
 
et si tu as une version >= 9i, alors écrit ta requête avec la syntaxe SQL92, à savoir en utilisant les jointures de type "right outer join", qui est à la fois plus explicite pour toi et pour oracle. si je comprends bien éventuellement ton problème, je pense d'ailleurs que la réponse se trouve dans cette syntaxe. la jointure entre b et c est un inner join et non un outer join


 
Merci de ta réponse MagicBuzz.
Je travaille en 10g. J'y ai pensé, et tenté de remplacer la jointure externe par une jointure interne entre B et C (AND b.NUM = c.NUM), mais à ce moment je n'ai plus aucun résultat! Et cela équivaut, sauf erreur de ma part, à un inner join non? Je ne suis pas très familiarisé avec l'écriture ANSI mais je vais approfondir en tout cas. Merci de la suggestion.

n°1787893
MagicBuzz
Posté le 17-09-2008 à 00:42:57  profilanswer
 

ben tout dépend. déjà, est-ce que tu as forcément des tupes dans chacune des trois tables, ou si lorsqu'une valeur n'est présente que dans A, tu peux quand même l'afficher en disant qu'il n'y a rien dans C ?

n°1787894
MagicBuzz
Posté le 17-09-2008 à 00:55:13  profilanswer
 

Exemple de ce que j'ai compris à 1h du matin :wahoo:
 
Sous SQL Server 2008. Mise à part les "go", les types et les [] d'échappement, la syntaxe devrait être rigoureusement la même.

Code :
  1. CREATE TABLE a (id numeric PRIMARY KEY, label varchar(30) NOT NULL)
  2. go
  3. CREATE TABLE b (id numeric NOT NULL, [num] numeric NOT NULL)
  4. go
  5. CREATE TABLE c ([num] numeric PRIMARY KEY, val numeric NOT NULL)
  6. go
  7. ALTER TABLE b ADD PRIMARY KEY (id, [num])
  8. go
  9. ALTER TABLE b ADD FOREIGN KEY (id) REFERENCES a (id)
  10. go
  11. -- Clé étrangère désactivées car les données de B font référence à des données qui n'existent pas dans C
  12. -- alter table b add foreign key ([num]) references c ([num])
  13. --go
  14. INSERT INTO a (id, label) VALUES (1, 'Ligne 1');
  15. INSERT INTO a (id, label) VALUES (2, 'Ligne 2');
  16. INSERT INTO a (id, label) VALUES (3, 'Ligne 3');
  17. INSERT INTO c ([num], val) VALUES (4, 7);
  18. INSERT INTO c ([num], val) VALUES (5, 8);
  19. INSERT INTO b (id, [num]) VALUES (1, 4);
  20. INSERT INTO b (id, [num]) VALUES (2, 5);
  21. INSERT INTO b (id, [num]) VALUES (2, 6);
  22. INSERT INTO b (id, [num]) VALUES (3, 7);
  23.  
  24. SELECT a.id, c.val
  25. FROM a INNER JOIN b ON b.id = a.id
  26. INNER JOIN c ON c.num = b.num;
  27.  
  28. SELECT a.id, c.val
  29. FROM a INNER JOIN b ON b.id = a.id
  30. LEFT OUTER JOIN c ON c.num = b.num;
  31.  
  32. SELECT a.id, c.val
  33. FROM a INNER JOIN b ON b.id = a.id
  34. INNER JOIN c ON c.num = b.num
  35. WHERE a.id = 2 AND c.val = 8;


 
Sortie :


 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
 
(1 ligne(s) affectée(s))
id                                      val
--------------------------------------- ---------------------------------------
1                                       7
2                                       8
 
(2 ligne(s) affectée(s))
 
id                                      val
--------------------------------------- ---------------------------------------
1                                       7
2                                       8
2                                       NULL
3                                       NULL
 
(4 ligne(s) affectée(s))
 
id                                      val
--------------------------------------- ---------------------------------------
2                                       8
 
(1 ligne(s) affectée(s))


Message édité par MagicBuzz le 17-09-2008 à 01:08:18
n°1787896
MagicBuzz
Posté le 17-09-2008 à 01:04:00  profilanswer
 

Donc pour moi c'est bêtement du inner join.
 
Si par contre, dans le cas où il n'y a pas d'entrée val = 8 pour id = 2, tu n'auras pas de ligne. Si tu veux une ligne avec id = 2 et val = null en sortie, alors c'est plus sioux :
 

Code :
  1. SELECT a.id, (SELECT MIN(c.val) FROM c INNER JOIN b ON b.num = c.num WHERE b.id = a.id AND c.val = 8) AS val
  2. FROM a
  3. WHERE a.id = 2;


(Ca doit pouvoir s'écrire autrement)
 


id                                      val
--------------------------------------- ---------------------------------------
2                                       8
 
(1 ligne(s) affectée(s))
 
id                                      val
--------------------------------------- ---------------------------------------
2                                       NULL
 
(1 ligne(s) affectée(s))


(premier coup avec la ligne existante dans C et second coup avec la ligne non existante dans C)
 
Le "MIN" c'est pour s'assurer qu'en cas de doublons dans VAL (deux lignes avec val = 8 pour des num différents rattachés au même id) la requête ne plante pas. Tu n'auras par contre qu'une seule ligne dans ce cas. Si tu veux avoir deux lignes, il faut déplacer la jointure de la sous-requête à la requête principale :
 

Code :
  1. SELECT a.id, (SELECT MIN(c.val) FROM c WHERE c.num = b.num AND c.val = 9) AS val
  2. FROM a
  3. INNER JOIN b ON b.id = a.id
  4. WHERE a.id = 2;


 


id                                      val
--------------------------------------- ---------------------------------------
2                                       NULL
 
(1 ligne(s) affectée(s))


Message édité par MagicBuzz le 17-09-2008 à 01:07:17
n°1788273
Ju -
Posté le 17-09-2008 à 15:46:18  profilanswer
 

Ok, j'ai peut-être trop simplifié mon problème, je vais essayer d'être plus clair.
Voici ma requête réécrite, version ANSI, selon tes conseils:
 


SELECT a1.id, c1.val, c2.val,
FROM A a1 INNER JOIN B b1 ON b1.id = a1.id
INNER JOIN C c1 ON c1.id = b1.num,
A a2 INNER JOIN B b2 ON b2.id = a2.id
INNER JOIN C c2 ON c2.id = b2.num
WHERE a1.id = 2
AND a2.id = 2
AND c1.num = 8
AND c2.num = 9


 
Explication:
Chaque ligne de A contient (ou non) une entrée dans la table B.
Chaque ligne de la table B pointe sur la table C
Certaines lignes de la table C sont du type qui m'intéresse (8 et 9, soit deux types, d'où la nécessité selon moi d'avoir a1 ET a2, c1 ET c2).
 
Je veux, pour l'entrée de A ayant id=2, une seule ligne en résultat, et qui contient:


ID    NUM    NUM
2     4        5


 
Mais avec la requête ci-dessus, je ne récupère aucun résultat...

n°1788281
omega2
Posté le 17-09-2008 à 16:20:56  profilanswer
 

Entre C1 et C2, la seule chose qui change c'est le contenu de la colonne "num", n'est ce pas, et tu n'as pas besoin qu'une ligne de A corresponde aux deux types de C recherché.
 
Dans ce cas pourquoi ne pas simplifier en ne gardant qu'une seule instance de la table C et en utilisant un "OR"?
 
Ca donnerait quelque chose du genre :

Citation :

SELECT A.id, C.val
FROM A INNER JOIN B ON B.id = A.id
INNER JOIN C ON C.id = B.num
WHERE a1.id = 2
AND (c1.num = 8
OR c2.num = 9)

n°1788299
Ju -
Posté le 17-09-2008 à 16:59:10  profilanswer
 

Salut Omega2 et merci.
Je suppose que la requête que tu proposais était:

Code :
  1. SELECT A.id, C.val
  2. FROM A INNER JOIN B ON B.id = A.id
  3. INNER JOIN C ON C.id = B.num
  4. WHERE a1.id = 2
  5. AND (c1.num = 8
  6. OR c1.num = 9)


 
laquelle me ramène deux lignes:


id  val
2   4
2   5


mais je ne veux qu'une seule ligne par id:


id  val  val
2   4    5


Je continue à chercher merci de vos lumières!
 
 

omega2 a écrit :

Entre C1 et C2, la seule chose qui change c'est le contenu de la colonne "num", n'est ce pas, et tu n'as pas besoin qu'une ligne de A corresponde aux deux types de C recherché.
 
Dans ce cas pourquoi ne pas simplifier en ne gardant qu'une seule instance de la table C et en utilisant un "OR"?
 
Ca donnerait quelque chose du genre :

Citation :

SELECT A.id, C.val
FROM A INNER JOIN B ON B.id = A.id
INNER JOIN C ON C.id = B.num
WHERE a1.id = 2
AND (c1.num = 8
OR c2.num = 9)



Message édité par Ju - le 17-09-2008 à 17:01:26
n°1788305
omega2
Posté le 17-09-2008 à 17:14:22  profilanswer
 

oups, oui : c1
 
Regarde la syntaxe pour faire des requêtes imbriqués telles que dans le dernier exemple de MagicBuzz. En utilisant cette méthode et en faisant une requête par "cX.num" tu peux obtenir le résultat que tu veux.

mood
Publicité
Posté le 17-09-2008 à 17:14:22  profilanswer
 

n°1788607
casimimir
Posté le 18-09-2008 à 13:48:24  profilanswer
 

si tu as un nombre indéterminé de val que tu souhaites avoir sur la même ligne -> PL/SQL


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Requête externe sur résultat de requête externe

 

Sujets relatifs
problème requête updateBloqué par une requete SQL
Sortir requête SQL d'une boucle[MySQL] Optimisation de requete
editeur requete intuitifconseil pour big requete SQL
[Resolu][C#, ASP.net / access] problème requete update[SQL Server]Concaténation des résultats d'une requête SQL
Ecrire en début de fichier? Rafraichir une page externe?faire retouner plusieurs ligne a une requete
Plus de sujets relatifs à : Requête externe sur résultat de requête externe


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR