Votre solution utilise une extension de la clause GROUP BY qui permet de regrouper par certains champs (dans ce cas, juste post_author
):
GROUP BY wp_posts.post_author
et sélectionnez des colonnes non agrégées:
SELECT wp_posts.*
qui ne sont pas répertoriés dans la clause group by ou qui ne sont pas utilisés dans une fonction d'agrégation (MIN, MAX, COUNT, etc.).
Utilisation correcte de l'extension de la clause GROUP BY
Ceci est utile lorsque toutes les valeurs des colonnes non agrégées sont égales pour chaque ligne.
Par exemple, supposons que vous ayez une table GardensFlowers
( name
du jardin, flower
qui pousse dans le jardin):
INSERT INTO GardensFlowers VALUES
('Central Park', 'Magnolia'),
('Hyde Park', 'Tulip'),
('Gardens By The Bay', 'Peony'),
('Gardens By The Bay', 'Cherry Blossom');
et vous voulez extraire toutes les fleurs qui poussent dans un jardin, où poussent plusieurs fleurs. Ensuite, vous devez utiliser une sous-requête, par exemple, vous pouvez utiliser ceci:
SELECT GardensFlowers.*
FROM GardensFlowers
WHERE name IN (SELECT name
FROM GardensFlowers
GROUP BY name
HAVING COUNT(DISTINCT flower)>1);
Si vous devez extraire toutes les fleurs qui sont les seules fleurs dans le garder à la place, vous pouvez simplement changer la condition HAVING HAVING COUNT(DISTINCT flower)=1
, mais MySql vous permet également d'utiliser ceci:
SELECT GardensFlowers.*
FROM GardensFlowers
GROUP BY name
HAVING COUNT(DISTINCT flower)=1;
pas de sous-requête, pas de SQL standard, mais plus simple.
Utilisation incorrecte de l'extension de la clause GROUP BY
Mais que se passe-t-il si vous sélectionnez des colonnes non agrégées qui ne sont pas égales pour chaque ligne? Quelle est la valeur que MySql choisit pour cette colonne?
Il semble que MySql choisisse toujours la PREMIÈRE valeur qu'il rencontre.
Pour vous assurer que la première valeur rencontrée est exactement la valeur souhaitée, vous devez appliquer un GROUP BY
à une requête ordonnée, d'où la nécessité d'utiliser une sous-requête. Vous ne pouvez pas le faire autrement.
Étant donné l'hypothèse que MySql choisit toujours la première ligne qu'il rencontre, vous triez correctement les lignes avant le GROUP BY. Mais malheureusement, si vous lisez attentivement la documentation, vous remarquerez que cette hypothèse n'est pas vraie.
Lors de la sélection de colonnes non agrégées qui ne sont pas toujours les mêmes, MySql est libre de choisir n'importe quelle valeur, de sorte que la valeur résultante qu'elle affiche réellement est indéterminée .
Je vois que cette astuce pour obtenir la première valeur d'une colonne non agrégée est beaucoup utilisée, et cela fonctionne généralement / presque toujours, je l'utilise aussi parfois (à mes risques et périls). Mais comme ce n'est pas documenté, vous ne pouvez pas vous fier à ce comportement.
Ce lien (merci ypercube!) L' astuce GROUP BY a été optimisé montre une situation dans laquelle la même requête renvoie des résultats différents entre MySql et MariaDB, probablement en raison d'un moteur d'optimisation différent.
Donc, si cette astuce fonctionne, c'est juste une question de chance.
La réponse acceptée à l'autre question me semble fausse:
HAVING wp_posts.post_date = MAX(wp_posts.post_date)
wp_posts.post_date
est une colonne non agrégée, et sa valeur sera officiellement indéterminée, mais ce sera probablement la première post_date
rencontrée. Mais puisque l'astuce GROUP BY est appliquée à une table non ordonnée, il n'est pas sûr de savoir quelle est la première post_date
rencontrée.
Il retournera probablement des articles qui sont les seuls articles d'un seul auteur, mais même cela n'est pas toujours certain.
Une solution possible
Je pense que cela pourrait être une solution possible:
SELECT wp_posts.*
FROM wp_posts
WHERE id IN (
SELECT max(id)
FROM wp_posts
WHERE (post_author, post_date) = (
SELECT post_author, max(post_date)
FROM wp_posts
WHERE wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY post_author
) AND wp_posts.post_status='publish'
AND wp_posts.post_type='post'
GROUP BY post_author
)
Sur la requête interne, je renvoie la date de publication maximale pour chaque auteur. Je prends ensuite en considération le fait que le même auteur pourrait théoriquement avoir deux messages en même temps, donc je ne reçois que l'ID maximum. Et puis je retourne toutes les lignes qui ont ces ID maximum. Il pourrait être rendu plus rapide en utilisant des jointures au lieu de la clause IN.
(Si vous êtes sûr que cela ID
ne fait qu'augmenter, et si ID1 > ID2
cela signifie également cela post_date1 > post_date2
, alors la requête pourrait être rendue beaucoup plus simple, mais je ne suis pas sûr que ce soit le cas).
post_author
etpost_date
ne suffisent pas pour obtenir une ligne unique, donc il doit y en avoir plus pour obtenir une ligne unique parpost_author