column X must appear in the GROUP BY clause or be used in an aggregate function
SELECT version();
version
-----------------------------------------------------------------------------------------------------------------------------
PostgreSQL 14.5 (Debian 14.5-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
Есть таблицы:
CREATE TABLE levels (
id SERIAL PRIMARY KEY,
title VARCHAR(61) NOT NULL
);
CREATE TABLE contents (
id SERIAL PRIMARY KEY,
title VARCHAR(255),
level_id INT NOT NULL REFERENCES levels(id)
);
В них есть какие-то записи, я пытаюсь выполнить такой запрос:
WITH contents2 AS (
SELECT
c.*,
(SELECT l.title FROM levels l WHERE l.id=c.level_id) AS level_name
FROM contents c
)
SELECT c.id, c.title, c.level_name
FROM contents2 c
GROUP BY c.id
На что postgres говорит мне:
ERROR: column "c.title" must appear in the GROUP BY clause or be used in an aggregate function
Я понимаю что значит эта ошибка, таким образом postgres говорит что для той или иной колонки в SELECT есть несколько вариантов для выдачи. Но в данном случае, абсолютно очевидно, что должно быть в c.title, там просто нет других вариантов, но почему он выдаёт мне эту ошибку? Мне надо писать каждую колонку в GROUP BY чтобы он не выкидывал эту ошибку?
Ответы (2 шт):
т.к. СУБД не понимает, что делать с этим полем, необходимо явно указать/
Необходимо все перечисляемые поля добавить в GROUP BY(по этим полям группируем данные)
WITH contents2 AS (
SELECT
c.*,
(SELECT l.title FROM levels l WHERE l.id=c.level_id) AS level_name
FROM contents c
)
SELECT c.id, c.title, c.level_name
FROM contents2 c
GROUP BY c.id, c.title, c.level_name
Поля, которые не перечислены в GROUP BY можно использовать в запросе, но только вместе с агрегатными функциями
WITH contents2 AS (
SELECT
c.*,
(SELECT l.title FROM levels l WHERE l.id=c.level_id) AS level_name
FROM contents c
)
SELECT c.id, count(c.title), count(c.level_name), count(*)
FROM contents2 c
GROUP BY c.id
Попробуйте:
WITH contents2 AS (
SELECT
c.*,
(SELECT l.title FROM levels l WHERE l.id=c.level_id) AS level_name
FROM contents c
)
SELECT c.id, MAX(c.title) AS title, MAX(c.level_name) AS level_name
FROM contents2 c
GROUP BY c.id
Выглядит как костыль, но на самом деле довольно часто используется и не захламляет предложение GROUP BY
UPD: для искушённых.
Сложность алгоритма сортировки +- O(N*Ln(N)) - поиск максимума O(N), т.е. MAX в предложении SELECT не только увеличивает читабельность кода, но и освобождает оптимизатор сервера от ненужных действий. Да, в MySQL по умолчанию оно и так сработает, но на мой взгляд это бага, а не фича.