Exécution d'un WITH ROLLUP
lors du regroupement par plusieurs champs, MySQL renvoie une ligne de cumul pour chaque groupe, ainsi que le résumé général:
CREATE TABLE test (name VARCHAR(50), number TINYINT);
INSERT INTO test VALUES
('foo', 1), ('foo', 1), ('foo', 2), ('foo', 3), ('foo', 3),
('bar', 1), ('bar', 2), ('bar', 2), ('bar', 2), ('bar', 3),
('baz', 1), ('baz', 2), ('bar', 2);
SELECT name, number, COUNT(1) FROM test GROUP BY name, number WITH ROLLUP;
+------+--------+----------+
| name | number | count(1) |
+------+--------+----------+
| bar | 1 | 1 |
| bar | 2 | 3 |
| bar | 3 | 1 |
| bar | NULL | 5 |
| baz | 1 | 1 |
| baz | 2 | 2 |
| baz | NULL | 3 |
| foo | 1 | 2 |
| foo | 2 | 1 |
| foo | 3 | 2 |
| foo | NULL | 5 |
| NULL | NULL | 13 |
+------+--------+----------+
Je ne suis pas intéressé par les rollups pour foo/bar/baz, seulement le résumé global. Quelle est la façon la plus efficace d'y parvenir?
SELECT * FROM
(
SELECT name, number, COUNT(1) `count` FROM test
GROUP BY name, number WITH ROLLUP
) A WHERE (ISNULL(name) + ISNULL(number)) <> 1;
ou
SELECT * FROM
(
SELECT name, number, COUNT(1) `count` FROM test
GROUP BY name, number WITH ROLLUP
) A WHERE ISNULL(name) = ISNULL(number);
Si vous n'avez besoin que du total, il est probablement plus efficace d'utiliser un union all
requête comme celle-ci:
select name, number, count(1)
from test
group by name, number
union all
select null, null, count(1)
from test;
Si vous avez de nombreux attributs, WITH ROLLUP
produira de nombreux sous-ensembles que vous jeterez simplement dans la sélection externe. Je ne pense pas que l'optimiseur MySQL se rendra compte qu'il peut les ignorer, mais ce n'est qu'une supposition.
Vous pouvez également essayer D'AVOIR:
SELECT name, number, COUNT(1)
FROM test GROUP BY name, number
WITH ROLLUP
HAVING (number is not null or name is null);
ou
HAVING (number is null) = (name is null)
Dans ce cas, le résumé global est égal au nombre d'enregistrements (fréquence).
SELECT count(1) FROM test;
Si vous êtes intéressé par le résumé global des chiffres,
SELECT SUM(numbers) FROM test;
Certes, si vous n'êtes intéressé que par le résumé global, vous devez simplement écrire une requête qui le demande:
SELECT null, null, count(*) FROM test
(Vous avez créé une table de test avec 13 lignes, regroupées sur chaque colonne avec un cumul, puis vous avez dit que vous n'étiez intéressé que par la ligne qui, effectivement, compte le nombre de lignes de la table .. alors faites-le)
Si vous êtes uniquement intéressé par les lignes de détail et le résumé global, c'est à cela que servent les ensembles de regroupement:
SELECT name, number, count(*) FROM test GROUP BY GROUPING SETS ((name, number), ())
L'ensemble vide donnera le résumé, l'ensemble nom + numéro donnera le détail. ROLLUP est l'équivalent de cet ensemble de regroupement:
((name, number), (name), ())