Proč to nefunguje s GROUP BY
SELECT *
nelze použít s GROUP BY
; je to neplatný SQL. GROUP BY
nevybírá řádky tabulky. Vytvoří skupiny řádků pomocí poskytnutých výrazů a poté z každé skupiny vygeneruje nový záznam a vypočítá každý sloupec tohoto nového záznamu pomocí hodnot zahrnutých ve výrazu.
Sloupce, které se objeví v SELECT
klauzule musí splňovat jedno z následujících pravidel:
- objeví se také v
GROUP BY
doložka; - se používají s
GROUP BY
agregační funkce ; - jsou funkčně závislé na sloupcích, které se objevují v
GROUP BY
doložka.
Zatímco *
je zkratka pro všechny názvy sloupců tabulek použitých v dotazu, pro váš dotaz pouze user
splňují jeden z výše uvedených požadavků.
Před verzí 5.7.5
MySQL neimplementovalo třetí pravidlo výše. Používá se k přijímání dotazů, které obsahují SELECT
klauzule, které nenásledují žádný z GROUP BY
požadavky. Hodnota vrácená dotazem pro takové sloupce byla neurčitá
.
Od verze 5.7.5 MySQL odmítá GROUP BY
dotazy, které splňují požadavky.
Řešení
Ať tak či onak, řešení vašeho problému nezahrnuje GROUP BY
. To lze snadno provést pomocí LEFT JOIN
se správnými podmínkami:
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
Jak to funguje
Spojí tabulku comments
, s aliasem lc
("lc" z "posledního komentáře" uživatele) proti sobě, s aliasem nc
("nc" z "novějšího komentáře"). Klauzule spojení odpovídá každému záznamu lc
se všemi položkami nc
které patří stejnému uživateli (lc.user = nc.user
) a jsou novější (lc.id < nc.id
; Předpokládal jsem, že ID jsou přidělována postupně a novější komentáře mají větší hodnoty pro id
).
Použití LEFT JOIN
zajišťuje, že každý řádek lc
se objeví ve výsledku spojení, i když v nc
nebyl nalezen žádný odpovídající řádek (protože neexistuje žádný novější komentář stejného uživatele). V tomto případě NULL
se používá místo polí nc
. WHERE
klauzule zachovává v konečné sadě výsledků pouze řádky, které mají NULL
v nc.id
; to znamená v lc
obsahují nejnovější komentář každého uživatele.
SELECT
klauzule obsahuje všechna pole lc
(ty z nc
všechny jsou NULL
, tak jako tak). ORDER BY
klauzuli lze použít k seřazení sady výsledků. ORDER BY lc.id DESC
na první místo umístí nejnovější komentáře a LIMIT
klauzule udržuje výslednou sadu na slušné velikosti.