Requète imbriquée

Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
- - Dernière réponse : rbellot
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
- 7 sept. 2010 à 08:08
Bonjour,

Je rencontre un problème de liaison de deux tables:
j'ai un première table qui contient des véhicules VEHIC et une autre table qui contient les enregistrements planning de ces véhicules.
Je souhaite pour une période donnée récupérer tous les enregistrement planning. Mais le problème est que je n'ai pas les véhicules qui ne sont pas utilisés au planning...et il me les faut.

Afin d'être optimal, j'ai créé une jointure et traité le problème du planning. Je cherche une solution élégante et performante (client/serveur)qui me permette d'y intégrer les véhicules absents du planning.

Une première piste est d'utiliser une requète intégrée : mais pas très optimale.
Une deuxième piste est de créer une deuxième requète derrière et de compléter la première: pas terrible non plus !

Qu'en pensez-vous ?

Merci pour vos réponses.

Richard
Afficher la suite 

14 réponses

Messages postés
7745
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
24 septembre 2014
28
0
Merci
Une simple requete sur la table VEHIC avec jointure externe gauche sur la table planning devrait suffire, non ?


[i][b]---- Sevyc64 (alias Casy) ----
[hr]# LE PARTAGE EST NOTRE FORCE #/b/i
Commenter la réponse de cs_casy
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
0
Merci
Merci Casy

Genre:
Select
Planning.Id_Vehic
...
...
Vehic.Id_Vehic
...
...
From
Vehic Left outer join Planning on vehic.id_Vehic = planning.id_vehic
Where
planning.dateDebut >= pdatedebut and planning.dateFin <= pdatefin
Order by
...

Résultat : si les véhicules ne sont pas dans le planning ils n'apparaissent pas. Hors il me les faut, même à vide.

Comment faire ?
Commenter la réponse de rbellot
Messages postés
7745
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
24 septembre 2014
28
0
Merci
Il n'apparaissent pas à cause de la clause Where.

Pour qu'ils apparaissent, il faut rajouter le cas ou il n'y a pas de planning, c'est à dire ou Planning.dateDebut et Planning.dateFin sont nuls

Where
(planning.dateDebut >= pdatedebut and planning.dateFin <= pdatefin)
OR
(planning.dateDebut is Null and planning.dateFin is null)


[i][b]---- Sevyc64 (alias Casy) ----
[hr]# LE PARTAGE EST NOTRE FORCE #/b/i
Commenter la réponse de cs_casy
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
0
Merci
Après essai le résultat est le même.

Si on paramètre avec une journée sans planification, il ne ramène rien.

En fait les dates ne sont pas null (si j'ai bien compris ?) mais l'enregistrement est absent dans le planning. Est ce que le Null = rubrique vide ?
Commenter la réponse de rbellot
Messages postés
7745
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
24 septembre 2014
28
0
Merci
Ok, je me suis un peu mélangé les pinceaux.
J'étais parti sur l'idée que les véhicules que tu ne vois pas n'avait pas du tout de planification. Or, ils ont bien des planifications mais en dehors de la plage souhaitée. Donc forcément ma requete ne marche pas.

Il faut effectivement des requetes imbriquées. La jointure se faisant ici, non pas sur la table planning, mais sur table temporaire ne contenant que les planifications dans la plage de date souhaité. D'ailleurs la jointure sera plutôt à ce moment là une externe droite :

SELECT P.Id_Vehic,...,V.Id_Vehic,..... FROM 
  (SELECT * FROM Planning 
   WHERE (Planning.dateDebut >= pdatedebut  and 
          Planning.dateFin <= pdatefin)
   ) P
RIGHT OUTER JOIN Vehic V ON P.Id_Vehic=V.Id_Vehic 


Attention, les champs "plannings" dans la clause SELECT ne viennent plus de la table Planning, mais de la table temporaire P

En espérant que cette fois-ci, ça marche

[i][b]---- Sevyc64 (alias Casy) ----
[hr]# LE PARTAGE EST NOTRE FORCE #/b/i
Commenter la réponse de cs_casy
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
0
Merci
Merci casy de venir bruler tes neurones avec moi
Excuses moi mais j'étais chez un client cet AM.

Voici le code que j'ai testé
SELECT
v.id_VEHIC AS id_VEHIC,
V.NBR_PLACE AS NBR_PLACE,
V.VehicActif AS VehicActif,
V.VehicAFF AS VehicAFF,
V.catVehic AS catVehic,
V.id_TY_VEHI AS id_TY_VEHI,
V.Cle_Rang AS Cle_Rang,
V.dateSup AS dateSup,
V.PLQ_NUM AS PLQ_NUM,
V.desig50 AS desig50,
P.PGCLEUNIK AS PGCLEUNIK,
P.date_debut AS date_debut,
P.Heure_Debut AS Heure_Debut,
P.date_fin AS date_fin,
P.HEURE_FIN AS HEURE_FIN,
P.Lib_planning AS Lib_planning,
P.lib_survol AS lib_survol,
P.Typ_Mission AS Typ_Mission,
P.Cli_Option AS Cli_Option,
P.Id_MISSION AS Id_MISSION,
P.id_VEHIC AS id_VEHIC,
P.Id_M_Vehic AS Id_M_Vehic,
P.IDLg_Mission AS IDLg_Mission,
P.IDINTTECH AS IDINTTECH
FROM
(SELECT * FROM PLANNING_VEHIC
WHERE (PLANNING_VEHIC.date_debut >= {pDateDebut} AND
PLANNING_VEHIC.date_fin <= {pDateFin})
) P
RIGHT OUTER JOIN VEHIC V ON P.id_VEHIC = V.id_VEHIC

ORDER BY
id_VEHIC ASC

et le résultat est identique: aucun enregistrement ne remonte quand je paramètre un jour sans enregistrement dans la table planning_vehic.

Pourrais tu m'expliquer la différence entre jointure gauche et droite: j'ai cru comprendre une différence de cardinalité L(1,0) et R(1,+).

Par rapport à ton code ta requète sur le planning me parait bonne, par contre la recherche des véhicules absents dans la table planning et présents dans la table vehicule semble poser un problème.
Est ce que l'utilisation de is not ne serait pas une solution peut être dans une autre sous requète concernant les véhicules ? Ce n'est pas très élégant...
Ou l'élimination d'une intersection ?

Merci
Commenter la réponse de rbellot
Messages postés
7745
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
24 septembre 2014
28
0
Merci
Je pense que ta requete génère une erreur sur la clause ORDER BY, le nom id_VEHIC est ambiguë.

En effet, dans ton résultat, tu as 2 champs (alias) dont le nom retourné est id_VEHIC, le moteur SQL ne doit pas savoir sur lequel faire le ORDER BY.

Soit tu donne à chaque champ un nom unique, soit dans la clause ORDER BY, tu précise de quelle table le champ vient : ORDER BY P.id_VEHIC


[i][b]---- Sevyc64 (alias Casy) ----
[hr]# LE PARTAGE EST NOTRE FORCE #/b/i
Commenter la réponse de cs_casy
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
0
Merci
Bonsoir,

J'ai supprimé la clause order by et je teste :

Si je teste sur un jour où il n'y a aucun enregistrement dans le planning, donc la requète devrait ramener au moins les véhicules: le résultat est "pas d'enregistrement"

Si je teste sur un jour où il y a des enregistrements, il généère une erreur de code sql sur : pourquoi, je ne sais.

Dans tous les cas si j'ai bien compris ton code,le right outer join portant sur vehic ne peut me semble-t-il satisfaire la condition car elle n'existe pas, l'enregistrement côté planning étant absent. Peut être existe-t-il une clause absent, is not ??? unknown ???

Merci

Richard (je suis absent demain, je pourrai lire ta réponse mes pas la tester avant samedi matin)
Commenter la réponse de rbellot
Messages postés
7745
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
24 septembre 2014
28
0
Merci
Pour ce qui est des jointures, je te conseille de lire ce document. Il t'apportera, j'espère, quelques précisions quant à leur fonctionnements.

http://sqlpro.developpez.com/cours/sqlaz/jointures/


Pour ce qui est de ta requete, l'absence de résultat ne vient pas (pour le moment en tout cas) d'un problème de jointure, mais simplement du fait que ta requete ne s'execute pas car elle comporte une erreur.

D'après le message que tu rapporte, ton moteur de base de donnée ne semble pas comprendre la syntaxe utilisée pour donner l'alias P à la requete intermédiaire.
Cette syntaxe marche telle quelle sous SQLServer. Je ne connais pas ton SGBD, mais il faudrait vérifier la syntaxe qu'il attend concernant les alias de tables.


[i][b]---- Sevyc64 (alias Casy) ----
[hr]# LE PARTAGE EST NOTRE FORCE #/b/i
Commenter la réponse de cs_casy
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
0
Merci
Bonjour Casy,

Effectivement tu as raison le problème vient de l'alias de la table temporaire
(SELECT * FROM PLANNING_VEHIC
WHERE (PLANNING_VEHIC.date_debut >= {pDateDebut} AND
PLANNING_VEHIC.date_fin <= {pDateFin})
) P

J'ai essayé avec AS P mais cela ne change rien.
J'ai également changé le nom de l'alias en pensant à un conflit de nommage, mais idem.
Le SGBD est windev. On peut utiliser l'alias pour les rubriques et les tables mais viviblement pas pour une requète imbriquée. J'ai cherché aujourd'hui sur internet une explication mais je n'ai rien trouvé.

J'ai essayé ceci
(SELECT * FROM PLANNING_VEHIC
WHERE (PLANNING_VEHIC.date_debut >= {pDateDebut} AND
PLANNING_VEHIC.date_fin <= {pDateFin})
) P
VEHIC AS v
Dans ce cas il prend le from et propose un résultat.
Par contre dès que je rajoute la requète imbriquée et que j'utilise l'alias => erreur.

Vois tu une autre solution ? peut être deux requètes séparées : la première traitant le planning et la deuxième faisant le complément des véhicules ?

Merci pour ton aide.

Richard
Commenter la réponse de rbellot
Messages postés
7745
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
24 septembre 2014
28
0
Merci
Je ne connais pas windev et sa gestion très particulière des bdd, peut-être qu'un alias sur une table n'est pas possible.

Il faudrait alors passer par une vrai table temporaire, mais déjà qu'en SQL je sais pas trop faire, je ne sais même pas si c'est possible en windev


[i][b]---- Sevyc64 (alias Casy) ----
[hr]# LE PARTAGE EST NOTRE FORCE #/b/i
Commenter la réponse de cs_casy
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
0
Merci
Dernier essai !

J'ai donc développé un système à double requète ce n'est pas le + performant ni le plus élégant mais cela marche.

Mais comme je suis un gars têtu je poursuis néanmoins la recherche de la bonne solution (d'autant plus que j'ai plusieurs requêtes à faire sur cette architecture).

J'ai donc utilisé l'éditeur graphique de windev 14 pour réaliser la jointure externe, et voilà ci-dessous le code sql généré qui ne fonctionne pas plus, car les véhicules absents du planning, sont également absents de la requête.

SELECT
PLANNING_VEHIC.PGCLEUNIK AS PGCLEUNIK,
PLANNING_VEHIC.Date_Debut AS Date_Debut,
PLANNING_VEHIC.Heure_Debut AS Heure_Debut,
PLANNING_VEHIC.Date_Fin AS Date_Fin,
PLANNING_VEHIC.Heure_Fin AS Heure_Fin,
PLANNING_VEHIC.Lib_planning AS Lib_planning,
PLANNING_VEHIC.lib_survol AS lib_survol,
PLANNING_VEHIC.Typ_Mission AS Typ_Mission,
PLANNING_VEHIC.Cli_Option AS Cli_Option,
PLANNING_VEHIC.Id_MISSION AS Id_MISSION,
PLANNING_VEHIC.Id_VEHIC AS Id_VEHIC,
PLANNING_VEHIC.Id_M_Vehic AS Id_M_Vehic,
PLANNING_VEHIC.IDLg_Mission AS IDLg_Mission,
PLANNING_VEHIC.IDINTTECH AS IDINTTECH,
VEHIC.NBR_PLACE AS NBR_PLACE,
VEHIC.VehicActif AS VehicActif,
VEHIC.VehicAFF AS VehicAFF,
VEHIC.catVehic AS catVehic,
VEHIC.id_TY_VEHI AS id_TY_VEHI,
VEHIC.Cle_Rang AS Cle_Rang,
VEHIC.dateSup AS dateSup
FROM
VEHIC LEFT OUTER JOIN PLANNING_VEHIC ON PLANNING_VEHIC.Id_VEHIC = VEHIC.id_VEHIC
WHERE
(
PLANNING_VEHIC.Date_Debut >= pDateDebut
AND PLANNING_VEHIC.Date_Fin <= pDateFin
AND VEHIC.VehicActif = pVehicActif
AND VEHIC.VehicAFF = pVehicAff
AND VEHIC.dateSup = ''
)
ORDER BY
pRangementTyVehic ASC,
pRangementOperateur ASC,
pRangementAlpha ASC,
pRangementCapacite ASC,
Date_Debut ASC,
Heure_Debut ASC,
Id_VEHIC ASC

Un avis sur ce code ?

Merci pour vos réponses et idées diverses et variées qui pourraient faire avancer le débat.

Richard
Commenter la réponse de rbellot
Messages postés
7745
Date d'inscription
mercredi 1 septembre 2004
Statut
Membre
Dernière intervention
24 septembre 2014
28
0
Merci
Non cette requete n'est pas bonne, car, comme on l'a vu, tu ne dois pas faire la jointure entre la table vehic et la table Planning, mais entre la table vehic et le résultat d'une première requete sur la table planning.


Je ne sais pas si tu peux le créer avec l'éditeur graphique, mais le cheminement c'est
- Faire une requete sur la table planning en filtrant sur ta plage de date
- Récupérer le résultat de cette requete comme une "table virtuelle" et faire une jointure externe droite avec la table vehic

Dommage que je puisse pas avoir windev pour pouvoir tester (bien que je n'ai pas d'à priori très positifs sur cet EDI, sans connaitre en plus).

[i][b]---- Sevyc64 (alias Casy) ----
[hr]# LE PARTAGE EST NOTRE FORCE #/b/i
Commenter la réponse de cs_casy
Messages postés
9
Date d'inscription
mercredi 15 juillet 2009
Statut
Membre
Dernière intervention
15 octobre 2010
0
Merci
Merci Casy

J'ai bien compris le sous ensemble mais je ne vois pas de solution pour le réaliser avec windev.

D'autre part dans une des docs windev il est dit clairement : "il est impossible d'effectuer des imbrications de jointures". Je ne sais pas très bien ce qu'ils entendent par là mais cela pourrait bien être les sous-ensembles en question.

Juste une petite question, lorsque l'on exécute une requète en C/S les données sont où : sur le serveur ou en local ?

En ce qui concerne windev c'est un très bon AGL, généralement il est très fort pour le cas général et permet de traiter le cas particulier avec des développements particuliers. Il existe assez peu de limites, celle ci en est une visiblement. Mais sans doute puis je contourner le pb par une autre architecture.

Merci pour tes réponses.

Richard
Commenter la réponse de rbellot