web-dev-qa-db-fra.com

Obtenez uniquement un résumé global AVEC ROLLUP et GROUP BY pour plusieurs champs

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?

7
yoshi
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);
3
RolandoMySQLDBA

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.

2
Lennart

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)
1
EoghanM

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;
0
SaintJokel

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), ())
0
Caius Jard