IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes et SQL. Discussion :

Requête sur table d'association avec critère de date [AC-2007]


Sujet :

Requêtes et SQL.

  1. #1
    Membre à l'essai
    Inscrit en
    Janvier 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut Requête sur table d'association avec critère de date
    Bonjour,

    j'ai deux tables, une de véhicules et une d'employés (appelés membres), qui sont associés par une table d'association appelée AFFECTATION avec ID_VEHICULE et ID_MEMBRE. La table AFFECTATION comporte en plus les dates de début et de fin d'affectation pour retracer à quel employé était affecté tel véhicule à telle période.
    Je cherche à savoir quel était le dernier membre affecté à tel véhicule, pour les véhicules restitués (DATE_RESTITUTION IS NOT NULL). Je me base sur la date de fin d'affectation.

    VEHICULE
    ID
    IMMAT
    DATE_RESTITUTION

    AFFECTATION
    ID
    ID_VEHICULE
    ID_MEMBRE
    DATE_FIN

    MEMBRE
    ID
    NOM
    PRENOM

    C'est une requête pour un état, donc je dois m'en sortir avec du pur SQL.

    Merci d'avance.

  2. #2
    Expert éminent
    Avatar de jimbolion
    Homme Profil pro
    Moulticien
    Inscrit en
    Janvier 2013
    Messages
    3 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Moulticien
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2013
    Messages : 3 150
    Points : 7 001
    Points
    7 001
    Billets dans le blog
    2
    Par défaut
    Dapangma,

    As tu jeté un oeil ici, le problème se rapproche du tien (à adapter en fonction de ton cas d'utilisation)

    http://www.developpez.net/forums/d14...-meme-periode/

    Je te joins la version du format de la base (un formulaire F_Res) simule le cas, le résultat étant issu de la requête R_Rep

    La base : Encodagev4.zip

    JimBoLion

  3. #3
    Membre à l'essai
    Inscrit en
    Janvier 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Merci Jimbolion, je regarde tout ça. Je reviens nourrir le fil ASAP.

  4. #4
    Membre à l'essai
    Inscrit en
    Janvier 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    J'ai regardé la base Encodage.
    Ma base sur le réseau est revenue à une version de février par magie (sûrement un écrasement ), donc je ne peux pas trop tester.
    Cependant il y a deux points qui complexifient le problème par rapport à cet exemple :
    - c'est un état basé sur un objet requête ; donc on ne peut pas se baser sur des valeurs d'un formulaire (du moins je ne sais pas comment faire)
    - surtout l'id ne peut pas porter sur un véhicule ; il porte sur une association véhicule - employé à un moment T. Un véhicule peut être affecté à un membre (le même ou un autre) plusieurs fois (et techniquement en même temps). J'arrive à obtenir la liste des affectations à un instant T mais il me faut le nom de l'employé (donc l'id employé) qui l'a eu en dernier. Donc un regroupement par véhicule, et une date de fin max, et une sélection de l'ID_MEMBRE... qui casse le regroupement.
    La question que je n'arrive pas à résoudre est : comment récupérer le membre sans casser le regroupement ?

  5. #5
    Chroniqueur Actualités
    Avatar de Michael Guilloux
    Homme Profil pro
    Data Consultant
    Inscrit en
    Juillet 2013
    Messages
    2 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Data Consultant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2013
    Messages : 2 919
    Points : 87 785
    Points
    87 785
    Billets dans le blog
    2
    Par défaut
    Salut à tous,
    @Dapangma, ce que je te propose, c'est qu'au niveau d'un formulaire AFFECTATION, tu codes un évènement à chaque nouvel enregistrement. Un évènement sur le champ ID_Vehicule, qui va supprimer l'enregistrement qui a la même valeur ID_Vehicule que le nouveau, avant d'insérer ce dernier. En d'autres mots, Un véhicule ne sera enregistré qu'une seule fois dans la table AFFECTATION et ce sera l'enregistrement correspondant à la dernière fois où il a été utilisé en donnant la date de restitution du véhicule et le dernier utilisateur.
    Si en plus tu comptes conserver l'historique des enregistrements supprimés, tu peux mettre en place un système d'archivage de ta table en stockant les enregistrements dans une AFFECTATION_Archive (requête Ajout) par exemple avant de les supprimer de la table AFFECTATION (requête Delete).
    C'est du bricolage, mais ça permet d'avoir dans ta table AFFECTATION uniquement le dernier employé pour chaque véhicule et la date de restitution.

  6. #6
    Membre à l'essai
    Inscrit en
    Janvier 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    @kkm90
    Merci de la suggestion.
    Oui, ça peut résoudre le problème... mais assez salement (et je n'aime pas trop).
    En plus :
    - ça fait faire du boulot pour modifier les requêtes dans le reste de l'appli pour pointer sur la table d'archivage.
    - c'est une problématique que je vais retrouver dans plusieurs endroits de mon appli.
    - j'aime bien apprendre, et là c'est un truc que j'aimerais vraiment savoir faire (même en SQL 'normal', non Access).
    Donc je garde ta solution de côté en attendant que ma base soit rétablie, mais si je pouvais avoir une solution propre bien comme il faut je préfèrerais nettement.

    Je pense que mettre un champ qui serait un flag (genre 'is_active') dans ma table AFFECTATION et que je mettrais à jour par VBA lors de l'affectation et de la désaffectation (sur formulaire ad hoc) serait un peu plus propre et éviterait de refaire toutes les requêtes.

    Je reste ouvert aux solutions.

  7. #7
    Expert éminent

    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    3 841
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 841
    Points : 7 975
    Points
    7 975
    Par défaut
    Bonjour,

    Je ne suis pas un grand spécialiste du SQL, mais je pense que la requête que je te propose avec les fonctions de domaines devrait te convenir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT T_Affectation.IdVehicule_FK AS Vehicule, Max(T_Affectation.Date_Fin) AS DateDerniere, T_Vehicule.Date_Restitution, DLookUp("[IdMembre_FK]","[T_Affectation]","[Date_Fin]=#" & Format([DateDerniere],"mm/dd/yyyy") & "# AND [IdVehicule_FK]=" & [Vehicule]) AS MembreDern, DLookUp("[Nom_Prenom]","[T_Membre]","[IdMembre]=" & [MembreDern]) AS NomMembre
    FROM T_Vehicule INNER JOIN T_Affectation ON T_Vehicule.IdVehicule=T_Affectation.IdVehicule_FK
    GROUP BY T_Affectation.IdVehicule_FK, T_Vehicule.Date_Restitution
    HAVING (((T_Vehicule.Date_Restitution) Is Null));
    Si un expert SQL passe, il devrait pouvoir nous transformer cela avec des sous-requêtes.

    Je joins la base test.

    Bonne continuation

  8. #8
    Membre à l'essai
    Inscrit en
    Janvier 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    @madefemere
    Merci beaucoup, ça fonctionne ; je pars là-dessus.
    J'attends quelques jours de voir si un expert SQL passe et nous (me ) fournit une solution 100% SQL avant de marquer 'résolu'.

  9. #9
    Expert éminent
    Avatar de jimbolion
    Homme Profil pro
    Moulticien
    Inscrit en
    Janvier 2013
    Messages
    3 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Moulticien
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2013
    Messages : 3 150
    Points : 7 001
    Points
    7 001
    Billets dans le blog
    2
    Par défaut
    Dapangma bonjour,

    madefemere


    J'ai repris ton exemple Mandresy et j'avoue ne pas comprendre le résultat (mais certainement je suis passé à côté de quelque chose).

    Je reprends le #1 de Dapangma :

    Je cherche à savoir quel était le dernier membre affecté à tel véhicule, pour les véhicules restitués (DATE_RESTITUTION IS NOT NULL). Je me base sur la date de fin d'affectation.
    Si je pars de ton exemple fourni, seuls 3 véhicules correspondent à ce cas d'utilisation :

    IdVehicule Immatriculation Date_Restitution
    2 BBB 2222 11/03/2014
    4 DDD 4444 15/03/2014
    6 FFFF 6666 22/03/2014

    Dans ton cas tu sors les véhicules 1, 3, 5 et 7 (donc l'inverse de la demande ?)

    Ensuite pour chacun de ces véhicules, la table affectation me donne donc le membre ayant la date de fin la plus grande (on imagine que le véhicule peut être rendu avant la date supposée). La requête suivant me permet donc d'établir la date Max de Fin de chaque véhicule :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT Max(T_Affectation.Date_Fin) AS MaxDeDate_Fin, T_Vehicule.IdVehicule
    FROM T_Vehicule INNER JOIN T_Affectation ON T_Vehicule.IdVehicule = T_Affectation.IdVehicule_FK
    WHERE (((T_Vehicule.Date_Restitution) Is Not Null))
    GROUP BY T_Vehicule.IdVehicule;
    J'obtiens donc le résultat suivant :

    MaxDeDate_Fin IdVehicule
    28/03/2014 2
    27/03/2014 4
    24/03/2014 6

    La requête suivant va donc partant du résultat obtenu connaître les membres dont la date de fin correspond à la date Max obtenue pour chaque véhicule dont une date de restitution est pas nulle. Nous établirons pour cela une jointure entre T_Affectations et la requête précedemment calculée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT Req_ListeVehiculesRestituesMax.MaxDeDate_Fin, T_Membre.IdMembre, T_Membre.Nom_Prenom, T_Vehicule.Immatriculation, T_Vehicule.IdVehicule
    FROM T_Vehicule INNER JOIN (T_Membre INNER JOIN (Req_ListeVehiculesRestituesMax INNER JOIN T_Affectation ON (Req_ListeVehiculesRestituesMax.IdVehicule = T_Affectation.IdVehicule_FK) AND (Req_ListeVehiculesRestituesMax.MaxDeDate_Fin = T_Affectation.Date_Fin)) ON T_Membre.IdMembre = T_Affectation.IdMembre_FK) ON T_Vehicule.IdVehicule = T_Affectation.IdVehicule_FK;
    Le résultat ainsi obtenu : Requête Req_DernierUtilisateurVehicules de la base

    MaxDeDate_Fin IdMembre Nom_Prenom Immatriculation IdVehicule
    28/03/2014 5 Paul Marie BBB 2222 2
    27/03/2014 1 Picard Eric DDD 4444 4
    24/03/2014 1 Picard Eric FFFF 6666 6

    Ci-joint la base avec les deux requêtes permettant d'obtenir ce résultat :

    ReqDernierUtilisateur2.zip


    Ceci dit, une petite remarque toutefois, ne serait-il pas judicieux d'intégrer l'heure de restitution d'un véhicule ? (le même véhicule peut t-il être prêté deux fois dans la même journée : le matin et l'AM par exemple).

    Si j'ai bien compris le problème

    JimBoLion

  10. #10
    Membre à l'essai
    Inscrit en
    Janvier 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Dans ton cas tu sors les véhicules 1, 3, 5 et 7 (donc l'inverse de la demande ?)
    Oui, c'est juste un IS NULL qui a été mis à la place d'un IS NOT NULL. Bonne remarque, mais je n'ai pas eu de problème pour corriger.

    Le résultat ainsi obtenu : Requête Req_DernierUtilisateurVehicules de la base

    MaxDeDate_Fin IdMembre Nom_Prenom Immatriculation IdVehicule
    28/03/2014 5 Paul Marie BBB 2222 2
    27/03/2014 1 Picard Eric DDD 4444 4
    24/03/2014 1 Picard Eric FFFF 6666 6
    Ca m'a l'air tout bon. La magie des requêtes imbriquées en Access...
    Je vérifie ça lundi à l'aube mais je vais déjà marquer 'résolu'. Merci beaucoup à vous deux.

    Ceci dit, une petite remarque toutefois, ne serait-il pas judicieux d'intégrer l'heure de restitution d'un véhicule ? (le même véhicule peut t-il être prêté deux fois dans la même journée : le matin et l'AM par exemple).
    Pour information, il s'agit de véhicules affectés la plupart du temps pour 3 - 4 ans. Il y a la date de désaffectation (table AFFECTATION) et la date de restitution (table VEHICULE) ; après désaffectation, on peut le réaffecter à quelqu'un d'autre ou le restituer, tout de suite ou plus tard. Donc il est intéressant d'indiquer la date de fin d'affectation et la date de restitution.

  11. #11
    Expert éminent

    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    3 841
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 841
    Points : 7 975
    Points
    7 975
    Par défaut
    Bonsoir Dapangma,

    Effectivement, je ne sais pas ce qui m'est passé par la tête, mais je pensais faire le contraire du contraire en rédigeant la requête (je n'ai abusé de rien en plus).

    @ Jimbolion, j'imaginais effectivement passé par 2 requêtes (classique), mais ça me tente tellement les fonctions de domaines proposées dans Access (Après, il faut voir surtout les différences dans les vitesses d'exécution).

    L'essentiel, j'imagine, c'est que Dapangma a compris comment corriger les erreurs. Ca le fait avancer

    Bonne continuation à vous tous

  12. #12
    Expert éminent
    Avatar de jimbolion
    Homme Profil pro
    Moulticien
    Inscrit en
    Janvier 2013
    Messages
    3 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Moulticien
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2013
    Messages : 3 150
    Points : 7 001
    Points
    7 001
    Billets dans le blog
    2
    Par défaut
    Mandresy,

    Comme j'avais voulu comparer tes résultats aux miens, je me suis en effet posé la question, vu qu'ils étaient diamètralement opposés.
    Comme quoi le contraire du contraire impacte facilement la réponse.

    Reste à Dapangma d'évaluer les performances sur chacune des méthodes !

    @++

  13. #13
    Membre à l'essai
    Inscrit en
    Janvier 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Bonjour à vous deux,

    finalement je n'ai pu m'y coller que ce matin, j'ai pu confirmer que ça fonctionne.

    Reste à Dapangma d'évaluer les performances sur chacune des méthodes !
    Je n'ai pas vraiment évalué les performances : d'une part je n'ai qu'un enregistrement qui correspond dans ma base, et d'autre part je n'ai aucun doute sur la lenteur d'exécution du code procédural par rapport à du SQL.
    En plus je préfère du pur SQL (même si là on est sur du SQL Access), question de goût personnel.

    Je vous donne mes requêtes finales :
    SousRequeteDateDesaffectation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT Max(AFFECTATION.DATE_FIN) AS DATE_DESAFFECTATION, VEHICULE.ID
    FROM VEHICULE INNER JOIN AFFECTATION ON VEHICULE.ID=AFFECTATION.ID_VEHICULE
    WHERE (((VEHICULE.DATE_RESTITUTION) Is Not Null))
    GROUP BY VEHICULE.ID;
    RequeteVehiculesRestitues
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    PARAMETERS [Entrez la date de début de période] DateTime, [Entrez la date de fin de période] DateTime;
    SELECT VEHICULE.IMMAT, VEHICULE.DATE_RESTITUTION, SousRequeteDateDesaffectation.DATE_DESAFFECTATION, MEMBRE.NOM, MEMBRE.PRENOM, MEMBRE.MATRICULE
    FROM VEHICULE INNER JOIN (MEMBRE INNER JOIN (SousRequeteDateDesaffectation INNER JOIN AFFECTATION ON (SousRequeteDateDesaffectation.DATE_DESAFFECTATION=AFFECTATION.DATE_FIN) AND (SousRequeteDateDesaffectation.ID=AFFECTATION.ID_VEHICULE)) ON MEMBRE.ID=AFFECTATION.ID_MEMBRE) ON VEHICULE.ID=AFFECTATION.ID_VEHICULE
    WHERE (((VEHICULE.DATE_RESTITUTION) Between [Entrez la date de début de période] And [Entrez la date de fin de période]))
    ORDER BY VEHICULE.DATE_RESTITUTION;
    Encore merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 16/12/2013, 16h16
  2. [MySQL] Requête sur table de jointure avec not in ou not exists
    Par GueloSuperStar dans le forum Langage SQL
    Réponses: 12
    Dernier message: 08/03/2013, 15h01
  3. Requête sur table avec des centaines de millions de lignes
    Par kaka83185 dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 24/01/2012, 15h05
  4. [AC-2003] Requête de non-concordance associée avec d'autres critères
    Par DuracellSubaquatique dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 08/09/2009, 11h44
  5. Requête sur table avec beaucoup de champs
    Par Lideln75 dans le forum Requêtes
    Réponses: 16
    Dernier message: 04/12/2008, 02h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo