Il existe une table messages
qui contient les données comme indiqué ci-dessous:
Id Name Other_Columns
-------------------------
1 A A_data_1
2 A A_data_2
3 A A_data_3
4 B B_data_1
5 B B_data_2
6 C C_data_1
Si je lance une requête select * from messages group by name
, le résultat sera le suivant:
1 A A_data_1
4 B B_data_1
6 C C_data_1
Quelle requête retournera le résultat suivant?
3 A A_data_3
5 B B_data_2
6 C C_data_1
Autrement dit, le dernier enregistrement de chaque groupe doit être renvoyé.
À l’heure actuelle, c’est la requête que j’utilise:
SELECT
*
FROM (SELECT
*
FROM messages
ORDER BY id DESC) AS x
GROUP BY name
Mais cela semble très inefficace. Y a-t-il d'autres moyens d'atteindre le même résultat?
MySQL 8.0 supporte maintenant les fonctions de fenêtrage, comme presque toutes les implémentations SQL populaires. Avec cette syntaxe standard, nous pouvons écrire les requêtes les plus importantes:
WITH ranked_messages AS (
SELECT m.*, ROW_NUMBER() OVER (PARTITION BY name ORDER BY id DESC) AS rn
FROM messages AS m
)
SELECT * FROM ranked_messages WHERE rn = 1;
Vous trouverez ci-dessous la réponse originale que j'ai écrite pour cette question en 2009:
J'écris la solution de cette façon:
SELECT m1.*
FROM messages m1 LEFT JOIN messages m2
ON (m1.name = m2.name AND m1.id < m2.id)
WHERE m2.id IS NULL;
En ce qui concerne les performances, une solution ou l'autre peut être meilleure, en fonction de la nature de vos données. Vous devez donc tester les deux requêtes et utiliser celle qui offre les meilleures performances compte tenu de votre base de données.
Par exemple, j'ai une copie du StackOverflow August data dump . Je vais l'utiliser pour l'analyse comparative. Il y a 1 114 357 lignes dans la table Posts
. Cela fonctionne sur MySQL 5.0.75 sur mon Macbook Pro 2.40GHz.
Je vais écrire une requête pour trouver le message le plus récent pour un ID utilisateur donné (le mien).
D'abord en utilisant la technique montrée par @Eric avec le GROUP BY
dans une sous-requête:
SELECT p1.postid
FROM Posts p1
INNER JOIN (SELECT pi.owneruserid, MAX(pi.postid) AS maxpostid
FROM Posts pi GROUP BY pi.owneruserid) p2
ON (p1.postid = p2.maxpostid)
WHERE p1.owneruserid = 20860;
1 row in set (1 min 17.89 sec)
Même l'analyse EXPLAIN
prend plus de 16 secondes:
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 76756 | |
| 1 | PRIMARY | p1 | eq_ref | PRIMARY,PostId,OwnerUserId | PRIMARY | 8 | p2.maxpostid | 1 | Using where |
| 2 | DERIVED | pi | index | NULL | OwnerUserId | 8 | NULL | 1151268 | Using index |
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
3 rows in set (16.09 sec)
Produisez maintenant le même résultat de requête en utilisant ma technique avec LEFT JOIN
:
SELECT p1.postid
FROM Posts p1 LEFT JOIN posts p2
ON (p1.owneruserid = p2.owneruserid AND p1.postid < p2.postid)
WHERE p2.postid IS NULL AND p1.owneruserid = 20860;
1 row in set (0.28 sec)
L'analyse EXPLAIN
montre que les deux tables peuvent utiliser leurs index:
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
| 1 | SIMPLE | p1 | ref | OwnerUserId | OwnerUserId | 8 | const | 1384 | Using index |
| 1 | SIMPLE | p2 | ref | PRIMARY,PostId,OwnerUserId | OwnerUserId | 8 | const | 1384 | Using where; Using index; Not exists |
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
2 rows in set (0.00 sec)
Voici le DDL pour ma table Posts
:
CREATE TABLE `posts` (
`PostId` bigint(20) unsigned NOT NULL auto_increment,
`PostTypeId` bigint(20) unsigned NOT NULL,
`AcceptedAnswerId` bigint(20) unsigned default NULL,
`ParentId` bigint(20) unsigned default NULL,
`CreationDate` datetime NOT NULL,
`Score` int(11) NOT NULL default '0',
`ViewCount` int(11) NOT NULL default '0',
`Body` text NOT NULL,
`OwnerUserId` bigint(20) unsigned NOT NULL,
`OwnerDisplayName` varchar(40) default NULL,
`LastEditorUserId` bigint(20) unsigned default NULL,
`LastEditDate` datetime default NULL,
`LastActivityDate` datetime default NULL,
`Title` varchar(250) NOT NULL default '',
`Tags` varchar(150) NOT NULL default '',
`AnswerCount` int(11) NOT NULL default '0',
`CommentCount` int(11) NOT NULL default '0',
`FavoriteCount` int(11) NOT NULL default '0',
`ClosedDate` datetime default NULL,
PRIMARY KEY (`PostId`),
UNIQUE KEY `PostId` (`PostId`),
KEY `PostTypeId` (`PostTypeId`),
KEY `AcceptedAnswerId` (`AcceptedAnswerId`),
KEY `OwnerUserId` (`OwnerUserId`),
KEY `LastEditorUserId` (`LastEditorUserId`),
KEY `ParentId` (`ParentId`),
CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`PostTypeId`) REFERENCES `posttypes` (`PostTypeId`)
) ENGINE=InnoDB;
UPD: 2017-03-31, la version 5.7.5 de MySQL a activé le commutateur ONLY_FULL_GROUP_BY activé par défaut (par conséquent, les requêtes GROUP BY non déterministes ont été désactivées). De plus, elles ont mis à jour l'implémentation GROUP BY. et la solution risque de ne plus fonctionner comme prévu, même avec le commutateur désactivé. Il faut vérifier.} _
La solution ci-dessus de Bill Karwin fonctionne bien lorsque le nombre d'éléments dans les groupes est plutôt petit, mais les performances de la requête deviennent mauvaises lorsque les groupes sont plutôt grands, car la solution requiert environ n*n/2 + n/2
de seulement IS NULL
comparaisons.
J'ai fait mes tests sur une table InnoDB de 18684446
lignes avec des groupes 1182
. La table contient les résultats de test pour les tests fonctionnels et a le (test_id, request_id)
comme clé primaire. Ainsi, test_id
est un groupe et je cherchais le dernier request_id
pour chaque test_id
.
La solution de Bill fonctionne déjà depuis plusieurs heures sur mon Dell e4310 et je ne sais pas quand elle va se terminer alors qu'elle fonctionne sur un indice de couverture (d'où using index
dans EXPLAIN).
J'ai quelques autres solutions basées sur les mêmes idées:
(group_id, item_value)
est la dernière valeur de chaque group_id
, c'est-à-dire la première pour chaque group_id
si nous parcourons l'index par ordre décroissant;3 façons dont MySQL utilise les index est un excellent article pour comprendre certains détails.
Solution 1
Celui-ci est incroyablement rapide, il faut environ 0,8 seconde sur mes 18M + lignes:
SELECT test_id, MAX(request_id), request_id
FROM testresults
GROUP BY test_id DESC;
Si vous souhaitez modifier l'ordre en ASC, placez-le dans une sous-requête, renvoyez uniquement les identifiants et utilisez-le comme sous-requête à associer au reste des colonnes:
SELECT test_id, request_id
FROM (
SELECT test_id, MAX(request_id), request_id
FROM testresults
GROUP BY test_id DESC) as ids
ORDER BY test_id;
Celui-ci prend environ 1,2 secondes sur mes données.
Solution 2
Voici une autre solution qui prend environ 19 secondes pour ma table:
SELECT test_id, request_id
FROM testresults, (SELECT @group:=NULL) as init
WHERE IF(IFNULL(@group, -1)=@group:=test_id, 0, 1)
ORDER BY test_id DESC, request_id DESC
Il renvoie également les tests dans un ordre décroissant. Il est beaucoup plus lent puisqu'il effectue un balayage d'index complet, mais il est là pour vous donner une idée de la façon de générer un nombre maximal de lignes pour chaque groupe.
L'inconvénient de la requête est que son résultat ne peut pas être mis en cache par le cache de la requête.
Utilisez votre sous-requête pour renvoyer le groupe correct, car vous êtes à mi-chemin.
Essaye ça:
select
a.*
from
messages a
inner join
(select name, max(id) as maxid from messages group by name) as b on
a.id = b.maxid
Si ce n'est pas id
vous voulez le maximum de:
select
a.*
from
messages a
inner join
(select name, max(other_col) as other_col
from messages group by name) as b on
a.name = b.name
and a.other_col = b.other_col
Ainsi, vous évitez les sous-requêtes et/ou les ordres corrélés dans vos sous-requêtes, qui ont tendance à être très lents/inefficaces.
Je suis arrivé à une solution différente, qui consiste à obtenir les ID du dernier message de chaque groupe, puis à sélectionner dans la table des messages en utilisant le résultat de la première requête comme argument d'une construction WHERE x IN
:
SELECT id, name, other_columns
FROM messages
WHERE id IN (
SELECT MAX(id)
FROM messages
GROUP BY name
);
Je ne sais pas comment cela fonctionne par rapport à certaines des autres solutions, mais cela a fonctionné de façon spectaculaire pour ma table avec plus de 3 millions de lignes. (4 secondes d'exécution avec plus de 1200 résultats)
Cela devrait fonctionner à la fois sur MySQL et SQL Server.
Solution par sous-requête fiddle Link
select * from messages where id in
(select max(id) from messages group by Name)
Solution Par condition de joint lien fiddle
select m1.* from messages m1
left outer join messages m2
on ( m1.id<m2.id and m1.name=m2.name )
where m2.id is null
La raison de ce message est de ne donner que le lien fiddle.
Je n'ai pas encore testé avec de grandes bases de données, mais je pense que cela pourrait être plus rapide que de joindre des tables
SELECT *, Max(Id) FROM messages GROUP BY Name
Voici un autre moyen d'obtenir le dernier enregistrement associé à l'aide de GROUP_CONCAT
avec order by et de SUBSTRING_INDEX
pour choisir l'un des enregistrements dans la liste.
SELECT
`Id`,
`Name`,
SUBSTRING_INDEX(
GROUP_CONCAT(
`Other_Columns`
ORDER BY `Id` DESC
SEPARATOR '||'
),
'||',
1
) Other_Columns
FROM
messages
GROUP BY `Name`
La requête ci-dessus regroupera tous les Other_Columns
qui sont dans le même groupe Name
et en utilisant ORDER BY id DESC
joignera tous les Other_Columns
dans un groupe spécifique dans un ordre décroissant avec le séparateur fourni dans mon cas j’ai utilisé ||
, en utilisant SUBSTRING_INDEX
sur cette liste un
Une approche très rapide est la suivante.
SELECT *
FROM messages a
WHERE Id = (SELECT MAX(Id) FROM messages WHERE a.Name = Name)
Résultat
Id Name Other_Columns
3 A A_data_3
5 B B_data_2
6 C C_data_1
Voici ma solution:
SELECT
DISTINCT NAME,
MAX(MESSAGES) OVER(PARTITION BY NAME) MESSAGES
FROM MESSAGE;
Voici deux suggestions. Premièrement, si mysql supporte ROW_NUMBER (), c'est très simple:
WITH Ranked AS (
SELECT Id, Name, OtherColumns,
ROW_NUMBER() OVER (
PARTITION BY Name
ORDER BY Id DESC
) AS rk
FROM messages
)
SELECT Id, Name, OtherColumns
FROM messages
WHERE rk = 1;
Je suppose que par "dernier" vous voulez dire dernier dans l'ordre de l'identifiant. Sinon, modifiez la clause ORDER BY de la fenêtre ROW_NUMBER () en conséquence. Si ROW_NUMBER () n'est pas disponible, voici une autre solution:
Deuxièmement, si ce n’est pas le cas, c’est souvent une bonne façon de procéder:
SELECT
Id, Name, OtherColumns
FROM messages
WHERE NOT EXISTS (
SELECT * FROM messages as M2
WHERE M2.Name = messages.Name
AND M2.Id > messages.Id
)
En d'autres termes, sélectionnez des messages pour lesquels il n'y a pas de message Id-later portant le même nom.
SELECT
column1,
column2
FROM
table_name
WHERE id IN
(SELECT
MAX(id)
FROM
table_name
GROUP BY column1)
ORDER BY column1 ;
Vous pouvez voir à partir d'ici aussi.
http://sqlfiddle.com/#!9/ef42b/9
PREMIÈRE SOLUTION
SELECT d1.ID,Name,City FROM Demo_User d1
INNER JOIN
(SELECT MAX(ID) AS ID FROM Demo_User GROUP By NAME) AS P ON (d1.ID=P.ID);
SECONDE SOLUTION
SELECT * FROM (SELECT * FROM Demo_User ORDER BY ID DESC) AS T GROUP BY NAME ;
Clairement, il y a beaucoup de façons différentes d'obtenir les mêmes résultats, votre question semble être de savoir quel est le moyen efficace d'obtenir les derniers résultats dans chaque groupe de MySQL. Si vous travaillez avec d'énormes quantités de données et supposez que vous utilisez InnoDB avec les versions les plus récentes de MySQL (telles que 5.7.21 et 8.0.4-rc), il se peut qu'il ne soit pas efficace.
Nous avons parfois besoin de le faire avec des tables contenant même plus de 60 millions de lignes.
Pour ces exemples, je vais utiliser des données avec seulement environ 1,5 million de lignes pour lesquelles les requêtes doivent trouver des résultats pour tous les groupes des données. Dans nos cas réels, nous aurions souvent besoin de renvoyer des données d'environ 2 000 groupes (ce qui, en théorie, n'exigerait pas un examen très approfondi des données).
Je vais utiliser les tableaux suivants:
CREATE TABLE temperature(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
groupID INT UNSIGNED NOT NULL,
recordedTimestamp TIMESTAMP NOT NULL,
recordedValue INT NOT NULL,
INDEX groupIndex(groupID, recordedTimestamp),
PRIMARY KEY (id)
);
CREATE TEMPORARY TABLE selected_group(id INT UNSIGNED NOT NULL, PRIMARY KEY(id));
La table de température contient environ 1,5 million d'enregistrements aléatoires et 100 groupes différents . Le groupe sélectionné est composé de ces 100 groupes (dans notre cas, cette valeur serait normalement inférieure à 20% pour tous les groupes).
Comme ces données sont aléatoires, cela signifie que plusieurs lignes peuvent avoir le même enregistrement timestamp. Ce que nous voulons, c'est obtenir une liste de tous les groupes sélectionnés par ordre de groupID avec le dernier horodatage enregistré pour chaque groupe. Si le même groupe a plus d'une ligne correspondante, alors le dernier identifiant correspondant de ces lignes.
Si hypothétiquement MySQL avait une fonction last () qui renvoyait les valeurs de la dernière ligne d'une clause ORDER BY spéciale, nous pourrions simplement faire:
SELECT
last(t1.id) AS id,
t1.groupID,
last(t1.recordedTimestamp) AS recordedTimestamp,
last(t1.recordedValue) AS recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
ORDER BY t1.recordedTimestamp, t1.id
GROUP BY t1.groupID;
dans ce cas, il n’aurait besoin que d’examiner quelques 100 lignes car il n’utilise aucune des fonctions GROUP BY habituelles. Ceci s'exécute en 0 secondes et est donc très efficace . Notez que normalement, dans MySQL, une clause ORDER BY suivrait la clause GROUP BY, mais cette clause ORDER BY est utilisée pour déterminer l'ORDER de la dernière fonction (), si c'était après GROUP BY, alors ce serait de commander les GROUPES. Si aucune clause GROUP BY n'est présente, les dernières valeurs seront les mêmes dans toutes les lignes renvoyées.
Cependant, MySQL n’a pas cela, aussi examinons différentes idées et prouvons qu’aucune d’entre elles n’est efficace.
Exemple 1
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
SELECT t2.id
FROM temperature t2
WHERE t2.groupID = g.id
ORDER BY t2.recordedTimestamp DESC, t2.id DESC
LIMIT 1
);
Cela a examiné 3 009 254 lignes et a pris environ 0,859 seconde le 5.7.21 et légèrement plus long sur 8.0.4-rc
Exemple 2
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM temperature t1
INNER JOIN (
SELECT max(t2.id) AS id
FROM temperature t2
INNER JOIN (
SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
FROM selected_group g
INNER JOIN temperature t3 ON t3.groupID = g.id
GROUP BY t3.groupID
) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
GROUP BY t2.groupID
) t5 ON t5.id = t1.id;
Cela a examiné 1 505 331 lignes et a pris environ 1,25 seconde le 5.7.21 et légèrement plus long sur 8.0.4-rc
Exemple 3
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM temperature t1
WHERE t1.id IN (
SELECT max(t2.id) AS id
FROM temperature t2
INNER JOIN (
SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
FROM selected_group g
INNER JOIN temperature t3 ON t3.groupID = g.id
GROUP BY t3.groupID
) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
GROUP BY t2.groupID
)
ORDER BY t1.groupID;
Cela a examiné 3 009 685 lignes et a pris environ 1,95 seconde le 5.7.21 et légèrement plus longtemps le 8.0.4-rc
Exemple 4
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
SELECT max(t2.id)
FROM temperature t2
WHERE t2.groupID = g.id AND t2.recordedTimestamp = (
SELECT max(t3.recordedTimestamp)
FROM temperature t3
WHERE t3.groupID = g.id
)
);
Cela a examiné 6.137.810 lignes et a pris ~ 2,2 secondes sur 5.7.21 et légèrement plus long sur 8.0.4-rc
Exemple 5
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM (
SELECT
t2.id,
t2.groupID,
t2.recordedTimestamp,
t2.recordedValue,
row_number() OVER (
PARTITION BY t2.groupID ORDER BY t2.recordedTimestamp DESC, t2.id DESC
) AS rowNumber
FROM selected_group g
INNER JOIN temperature t2 ON t2.groupID = g.id
) t1 WHERE t1.rowNumber = 1;
Cela a examiné 6 017 808 lignes et a pris environ 4,2 secondes sur 8.0.4-rc
Exemple 6
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM (
SELECT
last_value(t2.id) OVER w AS id,
t2.groupID,
last_value(t2.recordedTimestamp) OVER w AS recordedTimestamp,
last_value(t2.recordedValue) OVER w AS recordedValue
FROM selected_group g
INNER JOIN temperature t2 ON t2.groupID = g.id
WINDOW w AS (
PARTITION BY t2.groupID
ORDER BY t2.recordedTimestamp, t2.id
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
) t1
GROUP BY t1.groupID;
Cela a examiné 6 017 908 lignes et a pris environ 17,5 secondes sur 8.0.4-rc
Exemple 7
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
LEFT JOIN temperature t2
ON t2.groupID = g.id
AND (
t2.recordedTimestamp > t1.recordedTimestamp
OR (t2.recordedTimestamp = t1.recordedTimestamp AND t2.id > t1.id)
)
WHERE t2.id IS NULL
ORDER BY t1.groupID;
Celui-ci prenait une éternité, je devais donc le tuer.
Essaye ça:
SELECT jos_categories.title AS name,
joined .catid,
joined .title,
joined .introtext
FROM jos_categories
INNER JOIN (SELECT *
FROM (SELECT `title`,
catid,
`created`,
introtext
FROM `jos_content`
WHERE `sectionid` = 6
ORDER BY `id` DESC) AS yes
GROUP BY `yes`.`catid` DESC
ORDER BY `yes`.`created` DESC) AS joined
ON( joined.catid = jos_categories.id )
Si vous voulez la dernière ligne pour chaque Name
, vous pouvez attribuer un numéro de ligne à chaque groupe de lignes par la valeur Name
et l'ordre par Id
par ordre décroissant.
REQU&ECIRC;TE
SELECT t1.Id,
t1.Name,
t1.Other_Columns
FROM
(
SELECT Id,
Name,
Other_Columns,
(
CASE Name WHEN @curA
THEN @curRow := @curRow + 1
ELSE @curRow := 1 AND @curA := Name END
) + 1 AS rn
FROM messages t,
(SELECT @curRow := 0, @curA := '') r
ORDER BY Name,Id DESC
)t1
WHERE t1.rn = 1
ORDER BY t1.Id;
Existe-t-il un moyen d'utiliser cette méthode pour supprimer les doublons dans un tableau? L'ensemble de résultats est essentiellement une collection d'enregistrements uniques. Par conséquent, si nous pouvions supprimer tous les enregistrements qui n'étaient pas dans l'ensemble de résultats, nous n'aurions en réalité aucun doublon. J'ai essayé cela, mais MySQL a donné une erreur 1093.
DELETE FROM messages WHERE id NOT IN
(SELECT m1.id
FROM messages m1 LEFT JOIN messages m2
ON (m1.name = m2.name AND m1.id < m2.id)
WHERE m2.id IS NULL)
Existe-t-il un moyen de sauvegarder la sortie dans une variable temp, puis de supprimer de NOT IN (variable temp)? @ Bill Merci pour une solution très utile.
EDIT: Pense que j'ai trouvé la solution:
DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));
INSERT INTO UniqueIDs
(SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
(T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields
AND T1.ID < T2.ID)
WHERE T2.ID IS NULL);
DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);
La requête ci-dessous fonctionnera correctement selon votre question.
SELECT M1.*
FROM MESSAGES M1,
(
SELECT SUBSTR(Others_data,1,2),MAX(Others_data) AS Max_Others_data
FROM MESSAGES
GROUP BY 1
) M2
WHERE M1.Others_data = M2.Max_Others_data
ORDER BY Others_data;
Bonjour @Vijay Dev si votre table messages contient Id qui est une clé primaire à incrémentation automatique, puis pour récupérer le dernier enregistrement sur la clé primaire que votre requête devrait lire comme suit:
SELECT m1.* FROM messages m1 INNER JOIN (SELECT max(Id) as lastmsgId FROM messages GROUP BY Name) m2 ON m1.Id=m2.lastmsgId
Si la performance est vraiment votre préoccupation, vous pouvez introduire une nouvelle colonne sur la table appelée IsLastInGroup
de type BIT.
Définissez-le sur true sur les dernières colonnes et conservez-le à chaque ligne insérez/mettez à jour/supprimez. Les écritures seront plus lentes, mais vous bénéficierez des lectures. Cela dépend de votre cas d'utilisation et je ne le recommande que si vous vous concentrez sur la lecture.
Votre requête ressemblera donc à:
SELECT * FROM Messages WHERE IsLastInGroup = 1
nous verrons comment utiliser MySQL pour obtenir le dernier enregistrement d'un groupe par enregistrements. Par exemple, si vous avez cet ensemble de résultats.
id category_id post_title
1 1 Title 1
2 1 Title 2
3 1 Title 3
4 2 Title 4
5 2 Title 5
6 3 Title 6
Je souhaite pouvoir obtenir le dernier message de chaque catégorie, titre 3, titre 5 et titre 6. Pour utiliser les messages classés par catégorie, vous utiliserez le groupe MySQL Group by keyboard.
select * from posts group by category_id
Mais les résultats obtenus avec cette requête sont.
id category_id post_title
1 1 Title 1
4 2 Title 4
6 3 Title 6
Le groupe de retournera toujours le premier enregistrement du groupe dans le jeu de résultats.
SELECT id, category_id, post_title FROM posts WHERE id IN ( SELECT MAX(id) FROM posts GROUP BY category_id );
Cela renverra les messages avec les ID les plus élevés dans chaque groupe.
id category_id post_title
3 1 Title 3
5 2 Title 5
6 3 Title 6
Que dis-tu de ça:
SELECT DISTINCT ON (name) *
FROM messages
ORDER BY name, id DESC;
J'ai eu un problème similaire (sur postgresql difficile) et sur une table d'enregistrements 1M. Cette solution nécessite 1.7s vs 44s produits par celui avec LEFT JOIN . Dans mon cas, je devais filtrer le corrispondant de votre champ name avec les valeurs NULL, ce qui donnait des performances encore meilleures de 0,2 s.
select * from messages group by name desc
SELECT * FROM nom_table WHERE primaire_key IN (SELECT MAX (clé_primaire) FROM nom_table GROUP BY nom_colonne)
Vous pouvez grouper en comptant et aussi obtenir le dernier élément du groupe comme:
SELECT
user,
COUNT(user) AS count,
MAX(id) as last
FROM request
GROUP BY user
Avez vous vu https://github.com/fhulufhelo/Get-Last-Record-in-Each-MySQL-Group ? ça marche pour moi
$sql = "SELECT c.id, c.name, c.email, r.id, r.companyid, r.name, r.email FROM companytable c LEFT JOIN ( SELECT * FROM revisiontable WHERE id IN ( SELECT MAX(id) FROM revisiontable GROUP BY companyid )) r ON a.cid=b.r.id";