mysql DISTINCT

WRInaute passionné
Salut,
J'ai un problème de requête mysql.
Sur mon site -www j'ai une table "sorties" (id, id_topo, date, com)

Je voudrais selectionner les dix sorties les plus récentes (champ date) et ayant un champ id_topo distinct.

Vous savez comment faire ???

Merci
 
WRInaute occasionnel
Si tu es sous mysql en version < 4, tu ne peux pas faire de sous-requetes.
Alors il faut probablement (pas sûr), commencer par une requete du type:
Code:
select id_topo, max(date) as mdate from sorties group by id_topo order by mdate desc limit 10;
Puis la parser et requêter pour chaque ligne obtenue un truc dans le genre:
Code:
select * from sorties where id_topo = (idtoporecup) and date = (daterecup);

Mais il y a peut-être mieux... Et surtout, ça ne marche que si il y a un seul enregistement pour un id_topo et date donnés...
 
WRInaute discret
select distinct id_topo, id, date, comm order by date

ça devrait marcher comme ça non?
:lol: e-kiwi a poster avant moi, oups
 
WRInaute occasionnel
Je ne pense pas: si il a plusieurs ID par ID_TOPO...
En fait, jeroen, tu devrais nous dire quelles sont les contraintes et index sur ta table (clé primaire, unique keys)...
 
WRInaute accro
non id doit etre sa clé, donc unique, id topo la clé de la table topo ? ca doit etre pour ... hhm... faire un topo :)
oui colle la requete de création de ta base (tu peux la sortir avec phpmyadmin)
 
WRInaute passionné
e-kiwi a dit:
et "select distinct id_topo,id,date,comm order by date desc limit 0,10" tout simplement marche pas ?

Je crois que le distinct ne s'applique pas à un champ unique mais à toute la ligne, donc ça ne marche pas (il peut y voir 2 lignes distinctes avec le même id_topo).

id est unique (autoincrément)
id_topo n'est pas unique et fait référence au champ id (unique : autoincrément) de la table topos

Vous avez des idées ?
je suis [presque] sûr que l'on peut faire ça en 1 requête.....
 
WRInaute discret
select distinct id_topo, id, max(date ) as theDate
from sorties
group by id_topo
order by theDate DESC

à tester :wink:
 
WRInaute accro
>> il peut y voir 2 lignes distinctes avec le même id_topo

plus haut ->

>> ayant un champ id_topo distinct.

tu veux des id_topo distinct ou bien ?

c est pas clair. colle la structure de ta pages et qques enregistrements en exemple si tu veux qu'on t aide. faire du SQL sans connaitre la table cé pas simple
 
WRInaute occasionnel
jeroen a dit:
(...)je suis [presque] sûr que l'on peut faire ça en 1 requête.....

Ah ben des idées, j'en ai plein :)
Par exemple, ça, ça marche très bien:
Code:
select tb1.*
from
sorties as tb1,
(select id_topo, max(date) as mdate from sorties group by id_topo order by mdate desc limit 10) as tb2
where tb1.id_topo = tb2.id_topo
and tb1.date = tb2.mdate
Mais il faut un mysql v4.0 !!
 
WRInaute passionné
e-kiwi a dit:
>> il peut y voir 2 lignes distinctes avec le même id_topo

c'est ce que me fournirait sa solution, et c'est ca que je ne veux pas (je veux un id_topo distinct)

@ Yan Bilik
Y'a plus simple, en déclarant 2 fois la table et en faisant une jointure par exemple ??
y'a quoi comme version de mysql sur ovh 300GP ??
 
WRInaute occasionnel
jeroen a dit:
Y'a plus simple, en déclarant 2 fois la table et en faisant une jointure par exemple ??
y'a quoi comme version de mysql sur ovh 300GP ??
Si c'est comme le 60gp (et ça doit être le cas), c'est du mysql v3. Donc pas de sous-requêtes.
Concernant la jointure, c'est évidemment de ce côté qu'il faut regarder, mais là, comme ça, je ne sait pas trop comment faire.
Peux-tu déjà confirmer qu'avec un id_topo et une date donnés, on n'obtient qu'un seul enregistrement ?
 
WRInaute occasionnel
The Jedi a dit:
Et pourquoi pas un GROUP BY id_topo, c'est plus rapide et moins lourd.

A mon avis, c'est parce qu'un simple group by id_topo (avec un max(date) comme je lui suggérais plus haut) ne lui retourneras pas les ID.
Enfin, à lui de dire...
 
WRInaute passionné
Yan Bilik a dit:
The Jedi a dit:
Et pourquoi pas un GROUP BY id_topo, c'est plus rapide et moins lourd.

A mon avis, c'est parce qu'un simple group by id_topo (avec un max(date) comme je lui suggérais plus haut) ne lui retourneras pas les ID.
Enfin, à lui de dire...

Exacement, et pour les récupérer il faut que je fasse une jointure sur la même table...

Je crois avoir la solution, je teste et vous tiens au courant, merci.
 
WRInaute passionné
bon, j'ai pour l'instant ça :

SELECT s1.id_topo, max(s1.date) as maxdate, s2.id FROM sorties as s1, sorties as s2 WHERE xxxx GROUP BY s1.id_topo ORDER BY dte

xxx car je n'arrive pas à faire ma jointure entre s1 et s2 .....
Vous avez des idées ???
 
WRInaute impliqué
Code:
SELECT s1.id_topo, max(s1.date) as maxdate, s1.dte, s2.id
FROM sorties as s1
	INNER JOIN sorties as s2 (on s2.id = s1.id)
GROUP BY s1.id_topo ORDER BY s1.dte

PS : pour ordonner sur un champ faut le sélectionner ;)
 
WRInaute occasionnel
jeroen a dit:
y'a quoi comme version de mysql sur ovh 300GP ??
Pour info, j'ai vu un msg sur forums.ovh.com où un client 60gp a demandé le passage en mysql v4 à OVH, ce qu'ils ont fait...
Donc ça doit être possible !
A "The Jedi": ça a l'air parfait, ta requête ! Avec un order ... desc et limit 10, c'est bon, jeroen ?
 
WRInaute passionné
The Jedi a dit:
Code:
SELECT s1.id_topo, max(s1.date) as maxdate, s1.dte, s2.id
FROM sorties as s1
	INNER JOIN sorties as s2 (on s2.id = s1.id)
GROUP BY s1.id_topo ORDER BY s1.dte

Ca revient au même que ce que j'avais fait : le s2.id = s1.id ne marche pas, je me retrouve avec des résultats ou le id ne correspond pas à la date (lors du regroupement du id_topo, la date celectionnée est bien correcte -> max(date), mais le champ id n'est pas bon....

exemple avec 3 lignes (id, id_topo, date):
1 1 12 (sortie n°1 associée au topo n°1 effectuée à la date du 12)
2 2 13 (sortie n°2 associée au topo n°2 effectuée à la date du 13)
3 1 10 (sortie n°3 associée au topo n°1 effectuée à la date du 10)

Je voudrais que ça me sorte (la sortie n°3 est écrasée par la sortie n°1, car plus vieille) :
2 2 13
1 1 12

avec ta solution , le champ id ne correspond pas au champ max(date). Par exemple je peux avoir (ce que je ne veux pas) comme résultat :
2 2 13
3 1 12

je sèche...
 
WRInaute occasionnel
La jointure est faite sur l'iD. Ne devrait-elle pas être faite sur ID_TOPO et DATE ?
Code:
SELECT s1.id_topo, max(s1.date) as maxdate, s1.dte, s2.id
FROM sorties as s1
   INNER JOIN sorties as s2
   ON s2.id_topo = s1.id_topo and s2.date = maxdate
GROUP BY s1.id_topo ORDER BY s1.dte DESC
(peut-être dois-tu ajouter s2.date et s2.id_topo au SELECT pour autoriser la jointure sur ces champs, à voir).
On va y arriver, on va y arriver...

(edit) Pas bon, le coup du s1.date dans la requête, plutôt ça:
Code:
SELECT s1.id_topo, max(s1.date) as maxdate, s2.id
FROM sorties as s1
   INNER JOIN sorties as s2
   ON s2.id_topo = s1.id_topo and s2.date = maxdate
GROUP BY s1.id_topo ORDER BY maxdate DESC

(re-edit) Je ne maitrise pas les "inner join" et autres. Que donnerait la requête suivante:
Code:
SELECT s1.id_topo, max(s1.date) as maxdate, s2.id
FROM sorties as s1, sorties as s2
WHERE s2.id_topo = s1.id_topo
    AND s2.date = maxdate
GROUP BY s1.id_topo ORDER BY maxdate DESC
 
WRInaute passionné
Je vois que tu cogites comme moi :p
J'y avais bien pensé, mais le champ maxdate est inconnu dans la table sorties....

[edit]
La deuxième dersion que tu propose, c'est celle sur laquelle je bosse, et c'est exactement le même problème....
Il faut simplement selectionner le bon id... :roll:
 
WRInaute occasionnel
Dans la 3eme syntaxe, as-tu tjs le pb de maxdate inconnu ? Si oui, où ? Dans la clause WHERE ou dans la clause ORDER BY ?
D'après la doc, tu peux ordonner selon un numéro de champ plutôt qu'un nom de champ. Donc si le maxdate bloque sur le order by, essaye un
"ORDER BY 2 DESC"
 
WRInaute impliqué
Le INNER JOIN c'est pareil que le LEFT JOIN sauf que ça te retourne une ligne uniquement si la jointure retourne un résultat des 2 côtés. Le LEFT JOIN est moins rapide mais retourne une ligne à tous les coups.

Y'a 2 tables, A et B. La table A contient la colonne "ID" et un enregistrement (1 par exemple), la B contient une colonne "ID" aussi mais est vide.

Code:
SELECT A.ID, B.ID
FROM A
    INNER JOIN B ON (B.ID = A.ID)
WHERE A.ID = 1
Ca te retournera que dalle parce 1 n'existe pas dans l'autre table.

C'est pareil que
Code:
SELECT A.ID, B.ID
FROM A, B
WHERE B.ID = A.ID AND A.ID = 1
mais c'est plus propre et plus rapide (moins bordélique au niveaux des WHERE, ils ne servent vraiment plus qu'à filtrer tes résultats)

Code:
SELECT A.ID, B.ID
FROM A
    LEFT JOIN B ON (B.ID = A.ID)
WHERE A.ID = 1
Ca par contre, ça te retournera 1 ligne.
Code:
A.ID     B.ID
------------------------
1         NULL

En tous cas désolé mais je comprends pas trop l'histoire de la requête, tous les éléments sont éparpillés partout et j'ai vraiment trop la flemme de tout rassembler.
Si tu me files en MP la structure de tes tables et des données, avec EXACTEMENT un exemple de résultat que t'attends je veux bien chercher de mon côté ;)
 
WRInaute passionné
Yan Bilik a dit:
Dans la 3eme syntaxe, as-tu tjs le pb de maxdate inconnu ? Si oui, où ? Dans la clause WHERE ou dans la clause ORDER BY ?
D'après la doc, tu peux ordonner selon un numéro de champ plutôt qu'un nom de champ. Donc si le maxdate bloque sur le order by, essaye un
"ORDER BY 2 DESC"

c'est dans le WHERE.
Que dit la doc ?
On peut utiliser un max() dans un WHERE ??

jedi >
envoyé ! :roll:
 
WRInaute impliqué
Le max() tu peux pas l'utiliser dans le WHERE mais dans un HAVING. WHERE recherche sur des éléments existants, HAVING sur des éléments générés/calculés dans la requête.

^^
 
WRInaute impliqué
Bon écoute je crois que j'ai trouvé ton bonheur ;)

Code:
SELECT c1.id,c1.id_topo,max(c2.date) as maxdate
FROM `courses` c1
INNER JOIN courses c2 ON (c2.id_topo  = c1.id_topo)
GROUP BY c1.id_topo
ORDER BY maxdate DESC, id_topo DESC
 
WRInaute occasionnel
J'ai rien contre toi, The Jedi, mais si ça marche, ton truc, j'ai rien pané: avec le "group by c1.id_topo", comment la requête choisit le champ c1.id ?
Pff...
 
WRInaute impliqué
Ben écoute, il m'a filé sa table, son contenu, le résultat attendu et cette requête renvoie le résultat escompté.

PS : pourquoi devrais-tu avoir quelque chose contre moi ?? o_O
 
WRInaute occasionnel
The Jedi a dit:
pourquoi devrais-tu avoir quelque chose contre moi ?? o_O

Bah pour rien ! Je suis juste à côté de la plaque. Pas grave. Un guronzan et ça va repartir. Passons. Mais j'ai toujours pas compris comment on peut intégrer dans un SELECT un champ qui n'est pas repris dans le GROUP BY, et qui n'est pas non plus une fonction d'aggrégation.
Pour moi:
select id_topo, max(date) from sorties group by id_topo
ça fonctionne, mais :
select id_topo, max(date), id from sorties group by id_topo
Je vois pas comment ça peut marcher.

Enfin bon, te casses pas la tête, j'irais relire de la doc à l'occasion sur le sujet. Là, ça me gave.
 
WRInaute impliqué
Ben parce que tu fais un regroupement sur une clé, pas sur une colonne.
Imagine que tu aies 3 lignes de résultat
Code:
c1	c1	c3
--------------------
1	A	A
1	B	A
1	C	B

Si tu fais un group by c1, il "regroupe" les résultats par c1 et par défaut, récupère que la première ligne du lot. Ca a le même effet qu'un distinct mais en plus performant.
 
WRInaute occasionnel
The Jedi a dit:
Si tu fais un group by c1, il "regroupe" les résultats par c1 et par défaut, récupère que la première ligne du lot (...)

C'est une découverte pour moi. Sous Oracle, ce genre de manip ne passe absolument pas. Ce qui m'inquiète, c'est la notion de "première ligne"... Première en quoi ? Première stockée ? Première dans l'ordre de tri (éventuellement) indiqué ??
 
WRInaute passionné
> the jedi
Bon, ça marche pas, ton code me fait pas le bon résultat : c'est chaque fois le premier id du regroupement qui est pris, alors que je voudrais l'id qui corresponde au max(date).
Je' t'envoie mon résultat....
 
WRInaute passionné
Soution trouvée par Yan Bilik.

Yan Bilik a dit:
Tu vas rire, j'ai trouver un truc très con qui a l'air de marcher...
Code:
SELECT max(id), id_topo, max(date )  AS maxdate
FROM courses
GROUP  BY id_topo
ORDER  BY maxdate DESC , id_topo DESC, id DESC


Pourquoi ça a l'air de marcher: parceque ... par définition, le max(id) est corrélé au max(date), puisque le id est en auto-increment...

Tont con :oops:
Merci à tous les deux...
 
WRInaute discret
merci a Yan Bilik
moi aussi j'avais ce genre de tri a faire sur une struture identique
apres quelques heures de recherche et de lecture sur les differents tutoriaux Mysql pour trouver une solution, et voila je suis tombe sur ce topic qui m'a secouru
 
WRInaute impliqué
Yan Bilik a dit:
Si c'est comme le 60gp (et ça doit être le cas), c'est du mysql v3. Donc pas de sous-requêtes.
Non, tu dois pouvoir basculer en mysql 4 en passant par le manager > mutualisé > ton domaine > base de données. Je l'ai fait récemment pour un 90Plan mais je crois que cette option est dispo également pour les GP. Pas de sauvegarde à faire, c'est rapide, il suffit juste ensuite de modifier le nom du serveur dans tes paramètres de connexion à la base.

Voilà qui devrait régler ton problème :wink:

EDIT: oups, j'avais pas vu que la discussion avait plusieurs pages, ton pb est déjà résolu :roll: Mais l'info peut tout de même servir !
 
Discussions similaires
Haut