Защо не работи с GROUP BY
SELECT *
не може да се използва с GROUP BY
; това е невалиден SQL. GROUP BY
не избира редове от таблицата. Създава групи от редове, като използва предоставените изрази, след което от всяка група генерира нов запис и изчислява всяка колона от този нов запис, използвайки стойностите, включени в израза.
Колоните, които се показват в SELECT
клаузата трябва да отговаря на едно от следните правила:
- се появяват и в
GROUP BY
клауза; - се използват с
GROUP BY
агрегатни функции ; - са функционално зависими от колоните, които се показват в
GROUP BY
клауза.
Докато *
е пряк път за всички имена на колони на таблицата(ите), използвани от заявката, за вашата заявка само user
колона отговарят на едно от изискванията по-горе.
Преди версия 5.7.5
MySQL не е приложил третото правило по-горе. Използва се за приемане на заявки, които съдържат SELECT
колони на клаузи, които не следват нито една от GROUP BY
изисквания. Стойността, върната от заявката за такива колони, беше неопределена
.
От версия 5.7.5 MySQL отхвърля GROUP BY
заявки, които отговарят на изискванията.
Решението
Така или иначе, решението на вашия проблем не включва GROUP BY
. Може лесно да се постигне с помощта на LEFT JOIN
с правилните условия:
SELECT lc.*
FROM comments lc # 'lc' from 'last comment'
LEFT JOIN comments nc # 'nc' from 'newer comment'
ON lc.user = nc.user # both comments belong to the same user
AND lc.id < nc.id # 'nc' is newer than 'lc'
WHERE nc.id IS NULL # there is no 'newer comment'
ORDER BY lc.id DESC
LIMIT 10
Как работи
Той се присъединява към таблицата comments
, с псевдоним lc
("lc" от "последния коментар" на потребител) срещу себе си, псевдоним като nc
("nc" от "по-нов коментар"). Клаузата за присъединяване съответства на всеки запис на lc
с всички записи на nc
които принадлежат на един и същ потребител (lc.user = nc.user
) и са по-нови (lc.id < nc.id
; Предположих, че идентификаторите се присвояват последователно и по-новите коментари имат по-големи стойности за id
).
Използването на LEFT JOIN
гарантира, че всеки ред от lc
се появява в резултата от съединяването, дори когато не е намерен съответстващ ред в nc
(защото няма по-нов коментар от същия потребител). В този случай NULL
се използва вместо полетата на nc
. WHERE
клаузата запазва в крайния набор от резултати само редовете, които имат NULL
в nc.id
; това означава в lc
част съдържат най-скорошния коментар на всеки потребител.
SELECT
клаузата съдържа всички полета на lc
(тези от nc
всички са NULL
, така или иначе). ORDER BY
клаузата може да се използва за сортиране на резултатния набор. ORDER BY lc.id DESC
поставя най-новите коментари на първо място и LIMIT
клауза поддържа набора от резултати в приличен размер.