次の表があります( SQL Fiddleで確認してください )(問題を分解するために作成しました)。
_| ID | Word |
----------------
| 5 | "Hello" |
| 6 | NULL |
| 7 | "World" |
| 8 | "World" |
_
ここで、_GROUP BY Word WITH ROLLUP
_を使用して、各Wordの出現回数をカウントしたいと思います。 ROLLUPによって生成された行のWordカラムのNULLは、「total」に置き換える必要があります。
_SELECT
ID,
ifnull(Word, "total") as Word,
count(*) as occurrences
FROM test
GROUP BY Word WITH ROLLUP;
_
問題は、レコード内のNULL
も、wordsがNULLである行の数で置き換えることです。
_| ID | Word | occurrences |
|----|-------|-------------|
| 6 | total | 1 | <- Here lies the problem
| 5 | Hello | 1 |
| 7 | world | 2 |
| 7 | total | 4 |
_
それで、私はcount(Word)
を使用して、それがデータからのNULLであるか、ROLLUPによって作成されたNULLであるかを区別して、「空」または「合計」で置き換えることができます。
_SELECT
ID,
if(count(Word) = 0, "empty", ifnull(Word, "total")) as Word,
count(*) as occurrences
FROM test
group by Word with ROLLUP;
_
これは私のユースケースでは機能しますが、まだ欠陥があります。Wordがすべての行でNULLの場合、count(Word)
も合計を示す最後の行で0になります:( SQL Fiddle異なるデータ(レコード#6のみ) )
_| ID | Word | occurrences |
|----|-------|-------------|
| 6 | empty | 1 |
| 6 | empty | 1 | <- Word should be "total"
_
次の文は私が望む結果をもたらします:
_SELECT
ID,
ifnull(Word, "total") as Word,
count(*) as occurrences
FROM
(
SELECT
ID,
ifnull(Word, "empty") as Word
FROM test
) tmp
GROUP BY Word WITH ROLLUP
_
しかし、ここでのほとんどの回答では、サブクエリの使用は推奨されていないようなので、もっと良い解決策があるかどうか疑問に思っています。
あなたには「解決策」があるので、
より良い解決策があるかどうか私は思っています。
それについてコメントしたいと思います。いくつかの側面に焦点を当てましょう:
SELECT ID [...] GROUP BY Word
は、WITH ROLLUP
の有無に関係なく間違っています。 値が不明なフィールドを選択しています。特に、MySQLを使用すると、ランダムな値を返すことが公開されます。または、厳密モード(推奨、および最新バージョンのMySQLではデフォルト)を使用している場合、クエリが失敗します: 'db_9_b0ff7.test.ID' is n't in GROUP BY
原則として、最終的なクエリに問題はありません。両方のクエリ(IDなし)で説明を実行すると、次のようになります。
MariaDB [test]> EXPLAIN SELECT if(count(Word) = 0, "empty", ifnull(Word, "total")) as Word, count(*) as occurrences FROM test group by Word with ROLLUP\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra: Using filesort
1 row in set, 1 warning (0.00 sec)
Warning (Code 1052): Column 'Word' in group statement is ambiguous
MariaDB [test]> EXPLAIN SELECT ifnull(Word, "total") as Word, count(*) as occurrences FROM ( SELECT ifnull(Word, "empty") as Word FROM test ) tmp GROUP BY Word WITH ROLLUP\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra: Using filesort
1 row in set, 1 warning (0.01 sec)
通常、MySQLに対する憎しみは、MySQLの初期バージョンに対する制限のためです。私はそれが今完璧であると言っているわけではありません。MySQLの開発は、これまでと同じように、本格的なリレーショナルエンジンではなく、高速で簡単にインストールできる簡単なRDBMSに焦点を当てているため、依然として問題があります。 、ただし、適切な場所のサブクエリは問題ありません(結局のところ、一部のクエリでは、何があってもサブクエリが必要になります。使用方法は問題ありません-要約された行をもう一度調べるオーバーヘッドのみがあり、実際の取引では、フルセットと比較して重要ではないと思います。
ここの私のインスタンスでは、サブクエリは表示されていませんが、5.6のマテリアライズドサブクエリで確認できます: http://sqlfiddle.com/#!9/b0ff7/7 (It問題なく内側のクエリを実行してから、外側の部分を実行します)。インデックスは(filesortにより)間違いなくここで役立ちますが、それは最終的なレコード数によって異なります。インデックス(現在は存在しない)を使用できないため、サブクエリがパフォーマンスを低下させる可能性があります。特定のmysqlバージョンをテストし、そのようなインデックスを作成する必要があります。
最後の質問は、MySQLでサブクエリを使用せずにそれを実行することは可能ですか? 私は本当に方法がわかりません-結合を行うことはできましたが、それでもサブクエリに対するものです。私は 代替 と考えることができます:
SELECT * FROM (
SELECT Word,
count(*) as occurrences
FROM test
GROUP BY Word with rollup)
tmp
ORDER BY occurrences;
これにより、最後の行に概要が含まれるようになります(他にnullがある場合は、実際のnull値です)。順序は、null値のみの場合でも発生します。逆に、順序付けが必要なため、さらに遅くなる可能性があり、ここでもインデックスが必要であり、そのインデックスが使用される場合と使用されない場合があります。
サブクエリを回避し、このクエリを使用して入力した文字を最適化できます。
SELECT
ifnull(Word, "empty") as Word,
count(*) as occurrences
FROM test
GROUP BY ifnull(Word, "empty") WITH ROLLUP
;
これは基本的に、グループ化が実行される前に、null
の値を「空の」マーカーに置き換えます。
null
値を含む行にありますPostgreSQLにも同様のアプローチを使用できますが、特別なGROUPING
関数を提供しているため、SQL Serverには必要ありません。