[MySQL] SELECT une entrée, celle d'avant et celle d'après en 1 fois ?

SELECT une entrée, celle d'avant et celle d'après en 1 fois ? [MySQL] - SQL/NoSQL - Programmation

Marsh Posté le 29-04-2008 à 13:35:39    

Hello,
 
Y a-t-il moyen en un SELECT de récupérer une entrée de ma base ainsi que cette d'avant et celle d'après ?
 
J'ai une base photos avec :
 
| ID | NOM | DATE | CATEGORIE |
 
je veux sélectionner ma photo et avoir sous le coude le nom de celle d'avant et celle d'après, dans la même catégorie [:paysan]
Je voulais éviter de devoir faire trop de requêtes à la suite pour ne sortir que 3 entrées...
 
Merci


Message édité par darxmurf le 29-04-2008 à 13:38:13

---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 13:35:39   

Reply

Marsh Posté le 29-04-2008 à 13:41:29    

EDIT : ID est une clé primaire. Mais les numéros ID ne se suivent pas forcément en fonction de la catégorie


---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 13:48:14    

Si t'as que l'id de la photo sélectionnée comme base, j'vois pas trop d'autre solution que :
 

Code :
  1. SELECT * FROM tofs t WHERE t.id = <id_de_ta_tof>
  2. union
  3. SELECT * FROM tofs pt WHERE pt.category = t.category AND pt.date = (SELECT max(date) FROM tofs WHERE date < t.date)
  4. union
  5. SELECT * FROM tofs nt WHERE nt.category = t.category AND nt.date = (SELECT min(date) FROM tofs WHERE date > t.date)


 
edit: en fait c'est merdique, voir plus bas.


Message édité par sielfried le 29-04-2008 à 14:40:12

---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 29-04-2008 à 13:51:41    

effectivement j'ai un peu fouillé sur le net mais j'ai trouvé que des histoires avec UNION... je vais me tourner de ce côté donc :/
 
J'aurais pensé que MYSQL intègre une fonction de RANGE ou un truc du genre :)
 
Merci de l'info !


---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 14:01:34    

En fait y a probablement bien mieux :
 

Code :
  1. SELECT * FROM tofs t WHERE t.id = <id_de_ta_tof> AND t.date
  2. BETWEEN
  3. (SELECT MAX(date) FROM tofs pt WHERE pt.category = t.category AND pt.date < t.date)
  4. AND
  5. (SELECT MIN(date) FROM tofs nt WHERE nt.category = t.category AND nt.date > t.date)


Message édité par sielfried le 29-04-2008 à 14:01:52

---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 29-04-2008 à 14:06:14    

bon dans tous les cas ça fait 3 requêtes pour trouver 3 photos :)


---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 14:07:28    

Ouais enfin y en avait 5 dans ma première proposition. [:dawa]

Message cité 1 fois
Message édité par sielfried le 29-04-2008 à 14:07:41

---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 29-04-2008 à 14:08:13    

sielfried a écrit :

Ouais enfin y en avait 5 dans ma première proposition. [:dawa]


 
spa faux [:tinostar]


---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 14:35:37    

la première requete marche en mysql? parceque en oracle il me jetterait pour les alias
 
sinon la 2eme requete devrait etre ok mais il faut changer le AND en OR
 

Code :
  1. SELECT *
  2. FROM tofs t
  3. WHERE t.id = <id_de_ta_tof>
  4. OR t.date BETWEEN(SELECT MAX(date) FROM tofs pt WHERE pt.category = t.category
  5.              AND pt.date < t.date)AND(SELECT MIN(date) FROM tofs nt WHERE nt.category = t.category AND nt.date > t.date)

Reply

Marsh Posté le 29-04-2008 à 14:39:33    

Effectivement, étourderie. [:petrus75]
 
D'ailleurs en fait pas besoin de BETWEEN, juste deux OR avec des =.
 
edit tardif: bon en fait non, ça va pas du tout, t.date n'a aucun sens dans ces conditions.


Message édité par sielfried le 29-04-2008 à 16:45:04

---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 29-04-2008 à 14:39:33   

Reply

Marsh Posté le 29-04-2008 à 15:27:32    

Le min/max sur les date est une mauvaise idée: s'il y a plusieurs photos pour une date donnée, la requête plus haut peut potentiellement remonter plus de 3 lignes.

 

Je ferais un truc dans le genre:

Code :
  1. SELECT
  2. case when sign(T1.id - T2.id) > 0 then 'prev'
  3.      when sign(T1.id - T2.id) < 0 then 'next'
  4.      else 'curr' end AS item,
  5. case when sign(T1.id - T2.id) > 0 then max(T2.id)
  6.      when sign(T1.id - T2.id) < 0 then min(T2.id)
  7.      else T1.id end AS item,
  8.      T2.*
  9. FROM
  10. tofs T1
  11. INNER JOIN tofs T2 ON T1.category = T2.category
  12. WHERE  T1.id=<id_de_ta_tof>
  13. GROUP BY T1.id, sign(T1.id - T2.id)
  14. ORDER BY sign(T1.id - T2.id)


note: en plus si les indexes sont correctement réglés celà sera plus rapide ;)
note2: c'est du pur MySQL, ça risque de pas marcher sur autre chose ( en particulier a cause du group by)


Message édité par anapajari le 29-04-2008 à 15:28:53

---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 29-04-2008 à 16:16:36    

Ouais mais il a dit que les IDs étaient pas forcément dans l'ordre je crois. (Enfin en fait non après relecture, c'était ptete pas forcément ce qu'il voulait dire. [:petrus75])
 
Du coup j'ai supposé que ces "dates" étaient des datetime (auquel cas je pense que mon truc fonctionne).


---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 29-04-2008 à 16:28:06    

non en fait ce que je voulais dire c'est que si on fais un select de 3 images de la même cat, les ID ne seront pas forcément ID, ID+1, ID+2  
c'est pour ça qu'une requête avec WHERE ID=t.id-1 n'aurait pas joué :)


---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 16:31:04    

en passant, j'ai essayé de faire une bête requête  
SELECT MAX(date), name FROM table ... LIMIT 1
et il me retourne qu'il faut mettre un GROUP BY [:paysan] pourquoi ?


---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 16:34:06    

on peut mettre un min ou un max dans un case en mysql(quasi jamais utilisé)?
 
en oracle a la limite on pourrait en utilisant les min/max version fonction analytique, mais la il ralerait direct.

Reply

Marsh Posté le 29-04-2008 à 16:34:14    

darxmurf a écrit :

en passant, j'ai essayé de faire une bête requête  
SELECT MAX(date), name FROM table ... LIMIT 1
et il me retourne qu'il faut mettre un GROUP BY [:paysan] pourquoi ?


SELECT date, name FROM table ORDER BY date DESC LIMIT 1
 
edit : en fait ça répond pas a ta question
 
en fait, il ne sait pas quel name choisir.
Il faudrait faire SELECT date, name FROM table WHERE date=(SELECT max(date) FROM TABLE) je pense


Message édité par Paulp le 29-04-2008 à 16:36:35
Reply

Marsh Posté le 29-04-2008 à 16:34:57    

edit: j'ai rien dit mon truc marchera jamais, d'ailleurs celles d'au dessus non plus (faut forcément un join ou un union quelque part)

Message cité 1 fois
Message édité par sielfried le 29-04-2008 à 16:44:25

---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 29-04-2008 à 16:51:46    

sielfried a écrit :

Ouais mais il a dit que les IDs étaient pas forcément dans l'ordre je crois.


La requête que j'ai donnée plus haut elle a pas besoin que les IDs se suivent hein :o

sielfried a écrit :

Du coup j'ai supposé que ces "dates" étaient des datetime (auquel cas je pense que mon truc fonctionne).


Pas vraiment, tu peux très bien avoir plusieurs enregistrement avec exactement le même timestamp dans une table. Ca arrive même régulièrement quand tu as des  "insert into taTable ( ..., champs_date) select ... current_timestamp .

sielfried a écrit :

edit: j'ai rien dit mon truc marchera jamais, d'ailleurs celles d'au dessus non plus (faut forcément un join ou un union quelque part)


ça c'est sur [:dawak]

darxmurf a écrit :

en passant, j'ai essayé de faire une bête requête
SELECT MAX(date), name FROM table ... LIMIT 1
et il me retourne qu'il faut mettre un GROUP BY [:paysan] pourquoi ?


L'utilisation d'un aggregat (max, min, sum, count, ...) impose l'utilisation du group by sur les colonnes "non-aggrégées". MySQL fait preuve de souplesse la-dessus, mais uniquement jusqu'à un certain point.

 
casimimir a écrit :

on peut mettre un min ou un max dans un case en mysql(quasi jamais utilisé)?
en oracle a la limite on pourrait en utilisant les min/max version fonction analytique, mais la il ralerait direct.


on peut faire n'importe quoi avec MySQL ;)
mais moi ce qui me surprend le plus c'est qu'il accepte le T2.* dans le select sans qu'il soit dans le group by.

Message cité 1 fois
Message édité par anapajari le 29-04-2008 à 16:56:48

---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 29-04-2008 à 16:55:27    

Bon au final pour pas me faire chier et pour faire des manip supplémentaires, j'ai fais 3 requêtes séparées ... [:tinostar]
 
Merci quand même j'ai 2 ou 3 trucs qui me serviront par la suite dans tous vos posts :jap:


---------------
Des trucs - flickr - Instagram
Reply

Marsh Posté le 29-04-2008 à 17:12:28    

anapajari a écrit :


La requête que j'ai donnée plus haut elle a pas besoin que les IDs se suivent hein :o


 
Pas dans l'ordre != se suivent pas.
 
Genre t'ajoute une photo en lui foutant la date d'il y a trois semaines, je sais pas. [:dawa]
 
C'est assez débile pour une date, mais rien ne l'empêche techniquement (on a plutôt ce genre de cas avec des listes dans lesquelles on peut aller insérer un truc en plein milieu, auquel cas on peut pas se baser sur l'ID).


---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 29-04-2008 à 17:16:06    

pas tort :o
Mais dans ce cas là, au lieu de faire sign(T1.id - T2.id) suffit de faire sign(T1.date - T2.date) et ça marche pareil ...


---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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