web-dev-qa-db-ja.com

集計関数はORDERBY句で何ができますか?

私が植物のテーブルを持っているとしましょう:

id fruit
1  banana
2  Apple
3  orange

私はこれらを行うことができます

SELECT * FROM plant ORDER BY id;
SELECT * FROM plant ORDER BY fruit DESC;

これは明らかなことをします。

しかし、私はこれに噛まれました、これは何をしますか?

SELECT * FROM plant ORDER BY SUM(id);
SELECT * FROM plant ORDER BY COUNT(fruit);
SELECT * FROM plant ORDER BY COUNT(*);
SELECT * FROM plant ORDER BY SUM(1) DESC;

これらはすべて、最初の行(id = 1)のみを返します。

  1. アンダーフードで何が起こっているのですか?
  2. 集計関数がORDER BYで役立つシナリオは何ですか?
13
nawfal

表の列ではなく集計値を実際に選択すると、結果がより明確になります。

SELECT SUM(id) FROM plant ORDER BY SUM(id)

これにより、すべてのIDの合計が返されます。もちろん、これは役に立たない例です。集計では常に1つの行しか作成されないため、順序付けする必要がないためです。クエリで行qith列を取得する理由は、MySQLがランダムではなく決定論的でもない1つの行を選択するためです。あなたの場合、それがテーブルの最初の列であることが起こりますが、ストレージエンジン、主キーなどによっては、他の列が別の行を取得する場合があります。したがって、ORDERBY句のみでの集約はあまり役に立ちません。

通常は、特定のフィールドでグループ化してから、結果セットを何らかの方法で並べ替えます。

SELECT fruit, COUNT(*)
FROM plant
GROUP BY fruit
ORDER BY COUNT(*)

これはもっと興味深いクエリです!これにより、フルーツごとに1行と、そのフルーツの合計数が表示されます。さらにリンゴを追加してみると、順序が実際に意味をなし始めます。

完全な表:

+----+--------+
| id | fruit  |
+----+--------+
|  1 | banana |
|  2 | Apple  |
|  3 | orange |
|  4 | Apple  |
|  5 | Apple  |
|  6 | banana |
+----+--------+

上記のクエリ:

+--------+----------+
| fruit  | COUNT(*) |
+--------+----------+
| orange |        1 |
| banana |        2 |
| Apple  |        3 |
+--------+----------+
18
Emil Vikström

これらのクエリはすべて、SQL標準に準拠するSQLプラットフォームで構文エラーを発生させます。

SELECT * FROM plant ORDER BY SUM(id);
SELECT * FROM plant ORDER BY COUNT(fruit);
SELECT * FROM plant ORDER BY COUNT(*);
SELECT * FROM plant ORDER BY SUM(1) DESC;

たとえば、PostgreSQLでは、これらすべてのクエリで同じエラーが発生します。

エラー:列 "plant.id"は、GROUP BY句に含めるか、集計関数で使用する必要があります

つまり、GROUPBYを使用せずにドメイン集計関数を使用しているということです。 SQLServerとOracleは同様のエラーメッセージを返します。

MySQLのGROUPBYは、少なくとも標準的な動作に関する限り、いくつかの点で壊れていることが知られています。しかし、あなたが投稿したクエリは私にとって新しい壊れた振る舞いだったので、そのために+1します。

内部で何が行われているのかを理解しようとするのではなく、標準のGROUPBYクエリの記述を学ぶ方がよいでしょう。 MySQLwillは、私の知る限り、標準のGROUPBYステートメントを正しく処理します。

以前のバージョンのMySQLドキュメントは、GROUPBYと非表示の列について警告していました。 (参考文献はありませんが、このテキストはいたるところに引用されています。)

GROUP BY部分から省略した列がグループ内で一定でない場合は、この機能を使用しないでください。サーバーはグループから任意の値を自由に返すことができるため、すべての値が同じでない限り、結果は不確定です。

最近のバージョンは少し異なります

この機能を使用すると、不要な列の並べ替えやグループ化を回避して、パフォーマンスを向上させることができます。ただし、これは主に、GROUPBYで指定されていない各非集計列のすべての値が各グループで同じである場合に役立ちます。サーバーは各グループから任意の値を自由に選択できるため、それらが同じでない限り、選択される値は不確定です。

個人的には、SQLの機能indeterminateは考慮していません。

  1. このような集計を使用すると、クエリは暗黙のグループを取得し、結果全体が単一のグループになります。

  2. 集計をby順で使用すると、group byもある場合にのみ役立ちます。そのため、結果に複数の行を含めることができます。

2
Guffa