какие столбцы поместить в предложение MySQL GROUP BY - PullRequest
0 голосов
/ 16 июля 2009

Короче говоря, какие поля следует ставить после предложения GROUP BY?

SELECT questions.question_id, questions.title, questions.content, questions.view_count, questions.posted_on, users.user_id, users.group_id, users.username, users.first_name, users.last_name COUNT(answers.answer_id) AS answer_count 
FROM (questions) 
JOIN answers ON questions.question_id = answers.question_id 
JOIN users ON questions.user_id = users.user_id 
WHERE `questions`.`publish` = 'Y' AND `questions`.`deleted_at` IS NULL AND `users`.`blocked` = 'N' 
GROUP BY questions.question_id

я должен поставить все неагрегированные поля, упомянутые в SELECT, или только одно из них подходит? (например, просто question_id) Я запутался, потому что в любом случае результаты одинаковы. В чем разница?

Учебники в Интернете, кажется, дают пример использования только двух полей, одного агрегированного поля и одного нормального поля.

обновление: хорошо, похоже, я должен поставить их все, чтобы получить точный результат. Это подняло другие вопросы: насколько точна точность? Разве это не хорошо? Как насчет влияния на производительность?

Ответы [ 4 ]

1 голос
/ 27 июля 2011

MySQL получает обе опции, другие базы данных - нет. Другие базы данных (hsqldb, Oracle) заставят вас поместить все поля, выбранные в предложении GROUP BY. Когда каждый помещает все столбцы после предложения GROUP BY, результат обычно менее неоднозначен. MySQL "интерпретирует" ваш запрос как:

SELECT questions.question_id, FIRST_VALUE(questions.title), FIRST_VALUE(questions.content), FIRST_VALUE(questions.view_count), FIRST_VALUE(questions.posted_on), FIRST_VALUE(users.user_id), FIRST_VALUE(users.group_id), FIRST_VALUE(users.username), FIRST_VALUE(users.first_name), FIRST_VALUE(users.last_name) COUNT(answers.answer_id) AS answer_count 
FROM (questions) 
JOIN answers ON questions.question_id = answers.question_id 
JOIN users ON questions.user_id = users.user_id 
WHERE `questions`.`publish` = 'Y' AND `questions`.`deleted_at` IS NULL AND `users`.`blocked` = 'N' 
GROUP BY questions.question_id

Это если бы в MySQL была функция "FIRST_VALUE".

Поскольку вы группируете по уникальному идентификатору (questions.question_id), результаты совпадают. Если один группируется по неуникальному идентификатору, возвращаемые значения очень неоднозначны.

Единственное, в чем я не уверен, так это в том, что более эффективно распределить группу по одному полю. Я предполагаю, что БД достаточно умны, чтобы понимать, что вы группируете по уникальному идентификатору, и планировать выполнение соответственно, но я не уверен.

Если нет никакой разницы в эффективности - вы должны поставить все поля после GROUP BY, потому что это более стандартно. В противном случае решите, предпочитаете ли вы писать стандартный SQL вместо написания эффективного SQL.

1 голос
/ 16 июля 2009

«Для точного результата нужно поставить все неагрегированные столбцы»

Верно, но я бы добавил, что вы разместите все столбцы в том порядке, в котором вы хотите, чтобы они были сгруппированы (что может быть важно для вас?).

Редактировать : Точный означает, что если вы этого не сделаете, ваш запрос будет просто сбой. Что касается выступлений, чем больше полей в вашем GROUP BY, тем больше снижаются ваши выступления, но это не является сюрпризом

1 голос
/ 16 июля 2009

Вам нужно поместить все неагрегированные столбцы для точного результата.

0 голосов
/ 16 июля 2009

ты должен сделать: GROUP BY questions.question_id, questions.title, questions.content, questions.view_count, questions.posted_on, users.user_id, users.group_id, users.username, users.first_name, users.last_name

(т.е. все они)

или

у вас может быть другое внутреннее объединение для подсчета, так что вам просто нужно сделать это.

РЕДАКТИРОВАТЬ: вот пример второго варианта (не проверял, но должен работать)

SELECT questions.question_id, questions.title, questions.content, questions.view_count, questions.posted_on, users.user_id, users.group_id, users.username, users.first_name, users.last_name, r.AN_ANSWER_COUNT 
FROM (questions q) 
JOIN answers ON questions.question_id = answers.question_id JOIN users ON questions.user_id = users.user_id 

left join (SELECT question_id, COUNT(a.answer_id) AS AN_ANSWER_COUNT
                   FROM answers a

                    WHERE (your_condition)
                    GROUP BY question_id)r 
            on  q.question_id = a.question_id

WHERE `questions`.`publish` = 'Y' AND `questions`.`deleted_at` IS NULL AND `users`.`blocked` = 'N' 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...