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 MySQL Discussion :

Requête sur les dates futures plus une date passée


Sujet :

Requêtes MySQL

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut Requête sur les dates futures plus une date passée
    Bonsoir à toutes et tous,

    après avoir fouillé le forum et m'être trituré les méninges une bonne partie de la journée (et de la dernière nuit également), je me résous à faire appel à vos lumières ; j'en profite d'ailleurs pour m'excuser par avance si la réponse se trouve déjà dans vos archives.

    Je souhaite stocker dans une table des informations susceptibles d'être modifiées dans le temps. Par ailleurs je voudrais que les modifications soient enregistrées sans écraser l'ancienne valeur afin de conserver un historique. Enfin, je veux pouvoir enregistrer à l'avance des modification à compter d'une certaine date.

    Dans cette optique j'ai une table qui ressemble, en gros à ça :
    +-------+------------------+-------------+-----------------+
    |...id...|...parent_id...|...valeur...|.....début.....|
    +-------+------------------+-------------+-----------------+
    |...1....|........1.........|......10.....|..2012-01-13.| # l'item 1 est créé avec une valeur de 10
    |...2....|........2.........|......10.....|..2012-01-13.| # l'item 2 est créé avec une valeur de 10
    |...3....|........1.........|......15.....|..2012-01-15.| # l'item 1 prendra la valeur 15
    |...4....|........2.........|......50.....|..2012-01-18.| # l'item 2 prendra la valeur 50
    |...5....|........1.........|....100.....|..2012-01-20.| # l'item 1 prendra la valeur 100
    +-------+------------------+-------------+-----------------+

    Premièrement, je souhaite savoir si ma méthode n'a pas un gros vice caché que je n'aurais pas remarqué.

    Cette table me donne satisfaction sauf au moment d'afficher la fois la valeur courante et les modifications prévues : je ne parviens pas à sélectionner à la fois les valeurs futures (avec debut>CURDATE() ) et la valeur courante (avec debut<CURDATE() ORDER BY debut DESC LIMIT 0,1 ).

    Je ne parviens à mes fins qu'en faisant 2 requêtes et je me dis qu'un cas comme le mien ne doit pas être exceptionnel et qu'une solution doit exister. J'ai bien pensé à rajouter une colonne "fin" mais ça me semble redondant vu qu'on peut la déduire de la colonne "debut".

    Bref, j'ai besoin d'un peu d'aide pour monter ma super requête qui sélectionne la valeur courante à la date voulue ainsi que les modifications ultérieures.

    Je vous remercie par avance de l'attention que vous me prêterez; et bonne soirée

    Yann

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Bonjour,

    Une piste mais je ne suis pas satisfait de la requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    select a.parent_id, 
    max(case when a.debut = b.dt_cur then valeur end) as cur_val,
    max(case when a.dt_debut = b.dt_prev then valeur end) as prev_val
    from t_stock a
    inner join (
    select parent_id, max(case when debut <= current_date then dt_mvt end) as dt_cur,
    min(case when debut > current_date then dt_mvt end) as dt_prev
    from t_stock 
    group by parent_id) b on a.parent_id = b.parent_id and (a.debut = b.dt_cur or a.debut = b.dt_prev)
    group by a.parent_id
    edit: Sinon avez-vous pensez à utiliser un UNION ALL entre vos deux requêtes ?

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    Merci beaucoup !
    Je ne connaissait le principe de l'UNION ; je vais poursuivre mes recherche dans ce sens car ça me semble être une solution plus élégante que les jointures (j'avais un peu tenté ce type de requêtes mais ça vire très rapidement à l'usine à gaz).

    Je vous tiens au courant pour mettre un [résolu] dès que j'aurais établi ma requête définitive.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    Comme prévu, la clause UNION a parfaitement fait son office et je récupère ma sélection à l'aide de la requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ( SELECT id, valeur
    FROM ma_table 
    WHERE debut IN 
        ( SELECT max(debut) 
        FROM ma_table 
        WHERE debut<=CURDATE() 
        GROUP BY parent_id )
    ) UNION ALL ( 
    SELECT id, valeur
    FROM ma_table 
    WHERE  debut>CURDATE() )
    Merci beaucoup pour ce coup de main qui m'a permis d'apprendre un nouveau truc au passage.
    Yann

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    Bon, finalement, ma requête n'est pas si aboutie : la première partie, chargée de récupérer, pour chaque parent_id la dernière date n'est pas suffisamment sélective : elle identifie, pour un parent_id, la date la plus récente et renvoie toutes les lignes dont la valeur de la colonne 'debut' correspond, quelquesoit la valeur de parent_id... ça sort donc quelques valeurs périmées.
    Ma recherche continue donc...

  6. #6
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par yonn_b Voir le message
    Bon, finalement, ma requête n'est pas si aboutie : la première partie, chargée de récupérer, pour chaque parent_id la dernière date n'est pas suffisamment sélective : elle identifie, pour un parent_id, la date la plus récente et renvoie toutes les lignes dont la valeur de la colonne 'debut' correspond, quelquesoit la valeur de parent_id... ça sort donc quelques valeurs périmées.
    Ma recherche continue donc...
    Avez-vous essayez ma proposition ?

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    Bonsoir, merci de m'accorder votre temps.
    A vrai dire, j'ai un peu de mal à débrouiller votre requête : l'usage de 'dt_mvt' provoque une erreur du fait que cet alias n'a semble-t-il pas été défini. Et comme je patine un peu, je ne parviens pas à corriger l'erreur.

  8. #8
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par yonn_b Voir le message
    Bonsoir, merci de m'accorder votre temps.
    A vrai dire, j'ai un peu de mal à débrouiller votre requête : l'usage de 'dt_mvt' provoque une erreur du fait que cet alias n'a semble-t-il pas été défini. Et comme je patine un peu, je ne parviens pas à corriger l'erreur.
    hmm effectivement, remplacez dt_mvt par la date "début"

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    La requête que vous m'avez proposée ne renvoie malheureusement que la dernière date passée et pas les dates futures.
    Je suis donc retourner peaufiner mon UNION et j'ai enfin retrouvé le bonheur grâce à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT parent_id, max(debut) as debut, valeur
    FROM ma_table
    WHERE debut<=CURDATE()
    GROUP BY parent_id
    UNION ALL
    SELECT parent_id, debut, valeur
    FROM ma_table
    WHERE debut>CURDATE()
    L'alias du premier SELECT n'est là que pour uniformiser la sortie et faciliter le traitement ultérieur.
    Au final, la solution n'était pas si compliquée. Encore merci pour votre aide.
    Yann

  10. #10
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT parent_id, max(debut) AS debut, valeur
    FROM ma_table
    WHERE debut<=CURDATE()
    GROUP BY parent_id
    C'est pas bon ça, MySql va vous remontez n'importe quelle ligne pour la colonne "valeur"

    Quand on fait un group by toutes les colonnes du select non encadrées par un fonction d’agrégation (min, max, etc) doivent être présente dans la clause group by

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    ... en tous cas, on ne peut pas dire que vous avez manqué de patience avec le mauvais élève que je suis.

    Je n'ose vous soumettre ma nouvelle tentative de peur de connaître un nouvel échec.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT parent_id, debut, valeur
    FROM ma_table
    WHERE debut=(
        select max(debut) 
        from ma_table as t 
        where t.parent_id=ma_table.parent_id 
        AND debut<=CURDATE() 
        AND ma_table.parent_id=t.parent_id)
    UNION ALL
    SELECT parent_id, debut, valeur
    FROM ma_table
    WHERE debut>CURDATE()
    A première vue, les tests sur une petite table factice fonctionnent plutôt bien de mon coté, mais le diable se cache dans les détails parait-il, et j'ai forcément omis quelque chose pour pouvoir définitivement passer cette discussion en [RESOLU].
    Merci pour votre aide.
    Yann

  12. #12
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Bonjour,

    votre nouvelle requête me semble pas mal (attention, toute fois, vous avez dupliqué la condition sur le parent_id), même si niveau perf je me demande si ceci ne serai pas mieux :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT parent_id, debut, valeur
    FROM ma_table a
    inner join (select parent_id, max(debut) as debut
        from ma_table as  t
        where debut<=CURDATE()) b on a.parent_id = b.parent_id and a.debut = b.debut
    UNION ALL
    SELECT parent_id, debut, valeur
    FROM ma_table
    WHERE debut>CURDATE()
    Je ne connais pas assez l'optimiser de mysql pour savoir quelle solution choisir, à vous de vérifier les plans d'executions

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    J'ai testé votre requête pour comparer mais elle souffre d'un petit défaut : la partie qui sert à la jointure ne retourne qu'un seul résultat (la dernière date passée de la table) et pas la dernière date pour chaque parent_id.
    Du coup, je ne reçoit qu'un seul résultat passé alors que j'en voudrais un par parent_id.

    Au final, je vais me contenter pour le moment de ma solution ; évidemment si je parviens à optimiser la chose je vous le ferai savoir.

    Merci tout de même pour votre aide qui m'a permis d'en apprendre un peu plus sur le requêtage et qui m'a orienté dans la bonne direction.

    Yann

  14. #14
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par yonn_b Voir le message
    J'ai testé votre requête pour comparer mais elle souffre d'un petit défaut : la partie qui sert à la jointure ne retourne qu'un seul résultat (la dernière date passée de la table) et pas la dernière date pour chaque parent_id.
    Du coup, je ne reçoit qu'un seul résultat passé alors que j'en voudrais un par parent_id.

    Au final, je vais me contenter pour le moment de ma solution ; évidemment si je parviens à optimiser la chose je vous le ferai savoir.

    Merci tout de même pour votre aide qui m'a permis d'en apprendre un peu plus sur le requêtage et qui m'a orienté dans la bonne direction.

    Yann
    Oui effectivement j'ai oublié le group by dedans, désolé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    SELECT parent_id, debut, valeur
    FROM ma_table a
    INNER JOIN (SELECT parent_id, max(debut) AS debut
        FROM ma_table AS  t
        WHERE debut<=CURDATE()
        group by parent_id) b ON a.parent_id = b.parent_id AND a.debut = b.debut
    UNION ALL
    SELECT parent_id, debut, valeur
    FROM ma_table
    WHERE debut>CURDATE()

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 11/05/2011, 00h11
  2. Requète sur l'année d'après une date
    Par Marcopololo dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 01/07/2008, 19h11
  3. [Débutant] Calcul d'une date à partir d'une date de départ et d'une durée
    Par Marmotton76 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 11/04/2007, 10h39
  4. Réponses: 2
    Dernier message: 21/03/2007, 16h06
  5. Réponses: 14
    Dernier message: 09/01/2007, 16h19

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