8791 sujets

Développement web côté serveur, CMS

Bonjour,

J'ai une table commandes crée comme ceci :

create table commandes
(
id int unsigned not null auto_increment,
montant decimal(6,2),
date date not null,
id_client int unsigned not null,
primary key(id)
)ENGINE = MYISAM default character set utf8;


et je voudrai séléctionner les deux dernieres commandes de chaque clients par ordre
descendant.

La seule solution que j'ai trouvé est de faire la requête de séléction suivante pour chaque clients :

SELECT id_client, date
FROM commandes
WHERE id_client = 1
ORDER BY date DESC
LIMIT 2;


C'est assé lourd Smiley decu

N'y aurait-il pas une meilleur solution?

merci
Modifié par perfectionniste (16 Jun 2012 - 06:12)
SELECT id_client, date
FROM commandes
WHERE id_client = 1
ORDER BY date DESC
LIMIT 2;


Cette requête tu l'as déjà imbriqué dans une boucle pour sélectionner automatiquement tes utilisateurs ?
Salut, j'ai une solution que j'ai testé. Comme mon jeu d'essai était un peu simpliste, j'espère que je ne me suis pas planté.
SELECT id, id_client, date, num, prev
FROM (

SELECT  id as id,
               id_client as id_client,
              date as date,
              @i:=if (@prev=id_client,@i+1,1) as num,
              @prev:=id_client as prev

FROM `commandes`,
(SELECT @i:=0) r,
(SELECT @prev:='') s

ORDER BY id_client, date desc

) as xx
where num < 3

Cela se fait en deux temps :
1) dans le select interne, on sélectionne toutes les lignes de la table, triées sur id_client et sur date en ordre décroissant.

Pour chaque ligne, on ajoute deux nouvellse colonnes num et prev.
NUM, qui est un compteur est numéroté à partir de 1.
A chaque rupture de séquence basé sur la valeur de id_client, ce compteur est remis à 1.

L'autre colonne PREV, est d'abord testé avant d'être initialisé avec la valeur de id_client. La première fois, PREV est initialisé à vide car on ne connais pas la valeur de id_client. Le mieux aurait été de l'initialisé à la valeur low_value.

2) dans le select externe, si on fait un vidage complet, on remarque que le compteur NUM, prend des valeurs allant de 1 à N pour chaque valeur de id_client. Il suffit alors de prendre NUM < 3 pour obtenir les deux premières lignes.

J'espère que cela correspond à ta demande !
Pour des questions de performance, tu devrais organiser ta table, non pas sur ID (primary key), mais sur les critères de ce que tu désires faires, c'est à dire trié sur la clef majeur "id_client" et sur la clef mineur "date".

Mais comme je ne connais pas les autres usages de ta table, je ne peux pas me prononcer !

Sinon à quoi te sert le ID ? Je suppose à rien, sinon pour la primary key.
Si fonctionnellement elle ne te sert à rien, autant ne pas mettre cette colonne.
Il serait plus logique de placer des indéxs sur la colonne id_client et la colonne date
plutot que la colonne id (qui identifie chaque commande) Smiley lol

petit problemme seulement :
ATTENTION :

• MySQL ne peut utiliser qu’un seul Index par table
Modifié par perfectionniste (17 Jun 2012 - 19:39)
Sauf qu'une "primary key" n'est pas un index.
La "primary key" indique seulement comment sont rangés les lignes dans la table.
Comme ici, tu fais un balayage de la totalité de la table, l'index ne te sert à rien.
Par contre mettre les champs "id_client" et "date" comme "primary key" est une bonne idée.

Inversement si tu désires accéder ponctuellement à un enregistrement, par exemple un client donnée et à une date donnée, il serait judicieux de metre un index sur la "primary key".

Sinon, as-tu testé ma solution et est-ce que cela te convient ?
Aprés avoir téster ta solution qui est fonctionnel et trés rapide, j'ai finalement séléctionner toute la table trier pas ordre décroisant sur les dates puis avec deux trois boucle foreach et une fonction sort() j'en suit arrivé au même résultat mais je garde ta solution pour le jour ou j'aurai le niveau pour mieux la comprendre car elle est certainement mieux que la mienne Smiley smile
Dans ce que tu veux faire, il existe plusieurs solutions possibles comme par exemple sélectionner en PHP les lignes que tu désires récupérer. Tu peux aussi faire moitier moitier, c'est à dire une solution partielle en SQL et le complément en PHP. Ce sera moins propre mais cela à le mérite de fonctionner correctement.

Maintenant si tu ne maitrises pas trop les tables MySql et le langage de requête SQL, je te conseil vivement une solution tout en PHP.

La seule solution qui à mes yeux soit la plus pertinente pour ce genre de problème est bien celle qui aura la meilleure performance.

Comme je n'ai pas fait les tests de performances, je ne peux rien dire sur ma solution. Je te rappelle que ce genre de problème ne se traite pas à la légère car cela à des implications financières sur le cout de la bande passante. Mais je pense que ces considérations ne doivent pas trop te perturber. Smiley lol

Bonne continuation ! Smiley smile