Précédent   Forum des professionnels en informatique > Bases de données > MySQL > Requêtes
Requêtes Forum d'entraide sur les requêtes MySQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 13/01/2012, 20h45   #1
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
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
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/01/2012, 09h36   #2
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 655
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 655
Points : 2 657
Points : 2 657
Bonjour,

Une piste mais je ne suis pas satisfait de la requête :
Code :
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 ?
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 17/01/2012, 20h56   #3
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
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.
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/01/2012, 20h21   #4
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
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 :
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
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/01/2012, 20h53   #5
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
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...
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/01/2012, 22h30   #6
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 655
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 655
Points : 2 657
Points : 2 657
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 ?
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/01/2012, 22h44   #7
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
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.
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/01/2012, 23h49   #8
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 655
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 655
Points : 2 657
Points : 2 657
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"
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/01/2012, 16h43   #9
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
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 :
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
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/01/2012, 18h52   #10
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 655
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 655
Points : 2 657
Points : 2 657
Code :
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
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/01/2012, 22h21   #11
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
... 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 :
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
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/01/2012, 09h25   #12
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 655
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 655
Points : 2 657
Points : 2 657
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 :
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
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/01/2012, 22h04   #13
Invité régulier
 
Inscription : janvier 2012
Messages : 13
Détails du profil
Informations forums :
Inscription : janvier 2012
Messages : 13
Points : 6
Points : 6
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
yonn_b est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/01/2012, 08h59   #14
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 655
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 655
Points : 2 657
Points : 2 657
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 :
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()
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 23h25.


 
 
 
 
Partenaires

Hébergement Web