Ответ 1
Но почему я получаю Узбекистан за общую сумму?
Потому что вы НЕ ВЫБРАТЬ элемент, который вы GROUPING BY. Если вы сказали:
GROUP BY c.printable_name
Вы получите ожидаемый NULL. Однако вы группируете другой столбец, поэтому MySQL не знает, что имя_таблицы принимает участие в группе rollup-group и выбирает любое старое значение из этого столбца при объединении всех регистраций. (Таким образом, вы можете увидеть другие страны, кроме Узбекистана.)
Это часть более широкой проблемы с MySQL, которая разрешима для того, что вы можете SELECT в запросе GROUP BY. Например, вы можете сказать:
SELECT gender FROM registrations GROUP BY country;
и MySQL будет с радостью выбирать один из гендерных значений для регистрации из каждой страны, даже если нет прямой причинно-следственной связи (например, "функциональной зависимости" ) между страной и полом. Другие СУБД откажутся от вышеуказанной команды на том основании, что на страну не гарантируется один пол. (*)
Теперь, это:
SELECT c.printable_name AS 'Country', count(*) AS '#'
FROM registrations r
INNER JOIN country c ON r.country = c.country_id
GROUP BY country
в порядке, потому что существует функциональная зависимость между r.country и c.printable_name (если вы правильно описали свой country_id как ПЕРВИЧНЫЙ КЛЮЧ).
Однако MySQL с расширением ROLLUP немного взломан в том, как он работает. На этапе свертки в конце он запускает весь набор результатов перед группировкой, чтобы захватить его значения, а затем устанавливает столбец "по-порядку" в NULL. Он также не имеет нулевых других столбцов, которые имеют функциональную зависимость от этого столбца. Это, вероятно, должно, но MySQL в настоящее время не совсем понимает всю суть функциональных зависимостей.
Итак, если вы выберете c.printable_name, он покажет вам, какое значение имени страны выбрано в случайном порядке, и если вы выберете c.country_id, он покажет вам, какой из идентификаторов страны он случайно выбрал - даже если c.country_id является критерием соединения, поэтому он должен быть таким же, как r.country, что равно NULL!
Что вы можете сделать, чтобы решить эту проблему:
- группа вместо имени для печати; должно быть ОК, если имена для печати уникальны или
- выберите "r.country", а также имя для печати, и убедитесь, что для NULL или
- забудьте WITH ROLLUP и выполните отдельный запрос для конечной суммы. Это будет немного медленнее, но также будет совместимым с ANSI SQL-92, поэтому ваше приложение может работать с другими базами данных.
(*: MySQL имеет параметр SQL_MODE ONLY_FULL_GROUP_BY, который должен решить эту проблему, но он идет слишком далеко и позволяет вы выбираете столбцы из GROUP BY, а не столбцы, которые имеют функциональную зависимость от GROUP BY. Таким образом, он также приведет к сбою действительных запросов, что делает его вообще бесполезным.)