[MySQL] Select qui renvoie la valeur n-1 et +1 pour chaque enregistre

Select qui renvoie la valeur n-1 et +1 pour chaque enregistre [MySQL] - SQL/NoSQL - Programmation

Marsh Posté le 11-12-2012 à 10:01:49    

Bon,
 
Je vais essayer de faire clair.
Je suis pas un cador de MySQL et là je butte sur une requete:
 
J'ai une table qui contiens:
Horodatage (Index - Type DATETIME) , Variable
 
avec des horodatages qui sont a intervalles variables, ca donne çà par exemple
2012-12-07 17:14:46 , 12
2012-12-07 17:25:32 , 8
2012-12-07 17:28:16 , 9
2012-12-07 18:10:23 , 23
 
J'aimerai , via une reque obtenir un tableau avec pour chaque enregistrement:
L'horodatage, la valeur de la variable pour cet enregistrement, la valeur de la variable pour l'enregistrement suivant chronologiquement, la valeur de la variable pour l'enregistrement précédent chronologiquement.
 
Pour mon exemple, ca donnerait:
 
2012-12-07 17:14:46 , 12 , NULL, 8
2012-12-07 17:25:32 , 8 , 12, 9
2012-12-07 17:28:16 , 9 , 8 , 23
2012-12-07 18:10:23 , 23 , 9, NULL
 
 
Comment puis-je faire çà ?

Reply

Marsh Posté le 11-12-2012 à 10:01:49   

Reply

Marsh Posté le 11-12-2012 à 13:53:49    

Salut,
 
Sur ma base, j'aurai fait comme ça :  
 
SELECT  
--ici on trouve la valeur courante
PTR1.BEGIN_DATE, PTR1.ID AS ID_COURANT,  
--le COALESCE permet d'éviter le cas du premier ou du dernier ID
COALESCE(MAX(DRV1.ID_MAX_INF), -1) AS MAX_PRECEDENT, COALESCE(MIN(DRV2.ID_MIN_SUP), -1) AS MIN_SUIVANT
--ça c'est ma table, à remplacer
FROM POS_TRANSACTION PTR1
--on fait un left outer sur elle même pour le dernier cas
LEFT OUTER JOIN
 (
 SELECT PTR2.BEGIN_DATE AS MAX_INF, PTR2.ID AS ID_MAX_INF
 FROM POS_TRANSACTION PTR2
 ) AS DRV1 ON DRV1.MAX_INF < PTR1.BEGIN_DATE
--on fait la jointure sur la date, en prenant toutes les valeurs inférieures
--on fait un left outer sur elle même pour le premier cas
LEFT OUTER JOIN
 (
 SELECT PTR3.BEGIN_DATE AS MIN_SUP, PTR3.ID AS ID_MIN_SUP
 FROM POS_TRANSACTION PTR3
 ) AS DRV2 ON DRV2.MIN_SUP > PTR1.BEGIN_DATE
--on fait la jointure sur la date, en prenant toutes les valeurs supérieures
--si on veut toute la table, on supprime le WHERE
WHERE PTR1.ID = 1507
GROUP BY PTR1.BEGIN_DATE, PTR1.ID
--on regroupe sur la valeur courante
 
J'ai essayé d'être plus efficace (ici plus on avance et plus les comparaisons sont complexes), mais je n'ai pas trop le temps...
 
Bon courage,

Reply

Marsh Posté le 11-12-2012 à 20:39:57    

Wouch!

 

Je Ne pensais pas que ça serais aussi balaise.
Je teste ça demain!

Reply

Marsh Posté le 11-12-2012 à 21:39:46    

Hop!
WIP:
 
SELECT PTR1.sensortime, PTR1.sensor_0_1, PTR1.globalstatus, PTR1.power, COALESCE( DRV1.ID_MAX_INF, NULL ) AS PRECEDENT, COALESCE( DRV2.ID_MIN_SUP, NULL ) AS SUIVANT
FROM Aurora PTR1
LEFT OUTER JOIN (
 
SELECT PTR2.sensortime AS MAX_INF, PTR2.sensor_0_1 AS ID_MAX_INF
FROM Aurora PTR2
ORDER BY PTR2.sensortime DESC
) AS DRV1 ON DRV1.MAX_INF < PTR1.sensortime
LEFT OUTER JOIN (
 
SELECT PTR3.sensortime AS MIN_SUP, PTR3.sensor_0_1 AS ID_MIN_SUP
FROM Aurora PTR3
) AS DRV2 ON DRV2.MIN_SUP > PTR1.sensortime
GROUP BY PTR1.sensortime
LIMIT 0 , 30

Reply

Marsh Posté le 11-12-2012 à 21:53:18    

Salut,
 
Je ne suis pas sur que ça fonctionne... Tu ne récupère jamais clairement le MIN et le MAX apres tes jointures, du coup je pense que tu vas récupérer toutes les valeurs en dessous et au dessus de ta date. L'ORDER BY ne change rien pour moi, ça va juste te trier toutes les données dans ta requete, mais ca ne devrait pas sortir ce que tu veux.
 
De tête, ca devrait faire ça (les num représentent des dates et les lettres les valeurs) :
1 a
2 b
3 c
5 e
4 d
 
Apres ta requête, je pense que tu vas avoir :
2 b a c
2 b a d
2 b a e
3 c b d
3 c a d
3 c b e
3 c a e
Etc.
 
Mais pas uniquement les lignes avec juste le précédent et le suivant.
 
En plus ton GROUP BY doit reprendre tous les champs qui ne sont pas des regroupements (des champs calculés avec SUM, MAX, MIN etc.).


Message édité par Tibar le 11-12-2012 à 22:02:54
Reply

Marsh Posté le 12-12-2012 à 14:06:11    

Je comprends pas bien le mécanisme [:gratgrat]  
Du coup, je propose une autre approche :D  
 
Il y a un équivalent du "rownum" Oracle avec mySQL ?
Avec lui, on peut numéroter tous les enregistrements d'un résultat :

Code :
  1. select rownum num, la_date from (select la_date from la_table order by la_date)

Il n'y a plus qu'à joindre cette requête avec elle-même en décalant les numéros de +1, et de même en décalant les numéros de -1.
Ce qui donne :

Code :
  1. select tb0.num num                   -- le numero de l'enregistrement, pas forcement utile
  2.      , tb0.la_date ref               -- la valeur
  3.      , NVL(tb_pre.la_date ,'?') pre  -- la valeur precedente
  4.      , NVL(tb_post.la_date,'?') post -- la valeur suivante
  5. from (
  6.   select rownum num, la_date from (select la_date from la_table order by la_date)
  7. ) tb0 -- l'ensemble des enregistrements, tries et numerotes
  8. left join (
  9.   select rownum num, la_date from (select la_date from la_table order by la_date)
  10. ) tb_pre  on (tb_pre.num =(tb0.num-1)) -- on joint chaque resultat avec celui ayant le numero inferieur
  11. left join (
  12.   select rownum num, la_date from (select la_date from la_table order by la_date)
  13. ) tb_post on (tb_post.num=(tb0.num+1)) -- on joint chaque resultat avec celui ayant le numero superieur
  14. order by tb0.num;


 
A priori, ça donne le bon résultat :)


Message édité par mrbebert le 12-12-2012 à 14:07:00

---------------
Doucement le matin, pas trop vite le soir.
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed