J'ai une table de base de données comme celle-ci:
id version_id field1 field2
1 1 texta text1
1 2 textb text2
2 1 textc text3
2 2 textd text4
2 3 texte text5
Si vous n'y êtes pas parvenu, il contient plusieurs versions d'une ligne, puis des données textuelles.
Je veux l'interroger et renvoyer la version avec le numéro le plus élevé pour chaque identifiant. (donc les deuxième et dernière lignes uniquement dans ce qui précède).
J'ai essayé d'utiliser group par lors de la commande par version_id DESC - mais il semble que la commande soit postérieure à celle-ci, de sorte que cela ne fonctionne pas.
Quelqu'un a une idée? Je ne peux pas croire que ça ne peut pas être fait!
METTRE À JOUR:
Venez avec cela, qui fonctionne, mais utilise une sous-requête:
SELECT *
FROM (SELECT * FROM table ORDER BY version_id DESC) t1
GROUP BY t1.id
Cela s'appelle sélectionner le groupe maximum d'une colonne. Voici plusieurs approches différentes pour mysql.
Voici comment je le ferais:
SELECT *
FROM (SELECT id, max(version_id) as version_id FROM table GROUP BY id) t1
INNER JOIN table t2 on t2.id=t1.id and t1.version_id=t2.version_id
Cela sera relativement efficace, bien que mysql crée une table temporaire en mémoire pour la sous-requête. Je suppose que vous avez déjà un index sur (id, version_id) pour cette table.
C'est un défaut de SQL que vous deviez plus ou moins utiliser une sous-requête pour ce type de problème ( semi-jointures sont un autre exemple).
Les sous-requêtes ne sont pas bien optimisées dans mysql, mais les sous-requêtes non corrélées ne sont pas si mauvaises tant qu'elles ne sont pas si énormes qu'elles seront écrites sur le disque plutôt que dans la mémoire. Étant donné que dans cette requête n'a que deux entiers, la sous-requête peut contenir des millions de lignes bien avant que cela se produise, mais la sous-requête select * de votre première requête risque de souffrir de ce problème beaucoup plus tôt.
Je pense que cela le ferait, je ne sais pas si c'est le meilleur ou le plus rapide.
SELECT * FROM table
WHERE (id, version_id) IN
(SELECT id, MAX(version_id) FROM table GROUP BY id)
SELECT id, version_id, field1, field2
FROM (
SELECT @prev = id AS st, (@prev := id), m.*
FROM (
(SELECT @prev := NULL) p,
(
SELECT *
FROM mytable
ORDER BY
id DESC, version_id DESC
) m
) m2
WHERE NOT IFNULL(st, FALSE);
Pas de sous-requête, on passe à UNIQUE INDEX ON MYTABLE (id, version_id)
si vous en avez une (ce que je pense que vous devriez
Cette requête fera le travail sans groupe par:
SELECT * FROM table AS t
LEFT JOIN table AS t2
ON t.id=t2.id
AND t.version_id < t2.version_id
WHERE t2.id IS NULL
Il n'a pas besoin de tables temporaires.
C'est du pseudo-code mais quelque chose comme ça devrait marcher très bien
select *
from table
inner join
(
select id , max(version_id) maxVersion
from table
) dvtbl ON id = dvtbl.id && versionid = dvtbl.maxVersion
Je le fais habituellement avec une sous-requête:
select id, version_id, field1, field2 de datatable comme dt où id = (select id de datatable où id = dt.id commande par version_id desc limite 1)