web-dev-qa-db-ja.com

複数のフィールドの全体的な要約WITH ROLLUPおよびGROUP BYのみを取得する

WITH ROLLUP複数のフィールドでグループ化すると、MySQLは各グループのロールアップ行と全体的な概要を返します。

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 |
+------+--------+----------+

私はfoo/bar/bazのロールアップに飽き飽きしておらず、全体的な概要のみを読みました。これを達成するための最も効率的な方法は何ですか?

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;

または

SELECT * FROM
(
    SELECT name, number, COUNT(1) `count` FROM test
    GROUP BY name, number WITH ROLLUP
) A WHERE ISNULL(name) = ISNULL(number);
3
RolandoMySQLDBA

合計が必要な場合は、次のようなunion allクエリを使用する方が効率的です。

select name, number, count(1) 
from test 
group by name, number 
union all 
select null, null, count(1) 
from test;

多くの属性がある場合、WITH ROLLUPは多くのサブセットを生成しますが、それらは外部選択で捨てるだけです。 MySQLオプティマイザがそれらをスキップできることに気付かないと思いますが、それは単なる推測です。

2
Lennart

また、HAVINGを試すこともできます。

SELECT name, number, COUNT(1) 
FROM test GROUP BY name, number 
WITH ROLLUP 
HAVING (number is not null or name is null);

または

HAVING (number is null) = (name is null)
1
EoghanM

この場合、全体的な要約はレコードの量(頻度)に等しくなります。

SELECT count(1) FROM test;

数字の全体的な要約に興味があるなら

SELECT SUM(numbers) FROM test;
0
SaintJokel

確かに、全体的な概要だけに関心がある場合は、それを要求するクエリを記述するだけです。

SELECT null, null, count(*) FROM test

(ロールアップですべての列にグループ化された13行のテストテーブルを作成し、テーブルの行数を効果的にカウントする行だけに関心があると言ったので、それを行ってください。)

詳細行と全体的な概要のみに関心がある場合は、それがグループ化セットの目的です。

SELECT name, number, count(*) FROM test GROUP BY GROUPING SETS ((name, number), ())

空のセットは要約を提供し、名前と番号のセットは詳細を提供します。 ROLLUPは、このグループ化セットと同等です。

((name, number), (name), ())
0
Caius Jard