• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:GROUP BY/ORDER BYの併用で期待するORDERが得られま)

GROUP BY/ORDER BYの併用で期待するORDERが得られないケースがある

このQ&Aのポイント
  • MySQLのバージョンが4.0.xであり、サブクエリーが使えない状況で、GROUP BYとORDER BYを組み合わせたクエリで期待する結果を得ることができないケースがあります。
  • クエリの結果、group_idでグループ化し、idの最大値の行だけを取得し、さらにidの降順で並べ替えるように指定しています。
  • しかし、一部の場合において期待する結果が得られないことがあります。自己結合を考えたり、ASで命名した列をWHERE句に使用することを試みましたが、うまくいきませんでした。解決策があれば教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

まず、GROUP BYの使い方に誤りがあります。 標準SQLおよび主要なRDBMSの実装では、GROUP BY使用時、SELECT句での選択リストに書けるのは、 (1)GROUP BYで指定した列 (2)MAXやCOUNTなどの集約(集合)関数 (3)定数 といったものだけです。 なぜかというと、GROUP BYにより1個以上の行を集約する訳ですから、それ以外の列は、どの値を選べばいいかが決められません。 しかし、MySQLではこの部分に拡張仕様を持っていて、 「GROUP BYでグループ化した結果、結果が一意になるならSELECT句でその列名を書いてよい。一意にならないなら、結果は保証しないし、MySQLの標準の設定ではエラーにもしない」 という、誤りを誘発しやすい仕様になっています。 http://dev.mysql.com/doc/refman/5.1/ja/group-by-hidden-fields.html 例を示すと、 SELECT c1,MAX(c2),c3 FROM t1 GROUP BY c1 といった書き方は、c3の値が決められないため、標準SQLでは誤りですし、主要なRDBMSでもエラーになります。 しかし、MySQLでは、「c1でグループ化した結果、c3の値が一意になるならそういう書き方でいい。一意にならないなら、結果は保証しない。エラーにもしない」です。 これは、例えばidとnameが一対であるような場合、分かっていて利用するには便利なのですが、知らないで使っている人、特に初心者が多いと感じでいます。 本来は、 SELECT id,name,SUM(score) FROM t1 GROUP BY id,name と書かなければだめなものを SELECT id,name,SUM(score) FROM t1 GROUP BY id とできるというものです。 逆にいうと、上の書き方と下の書き方で結果が違うなら、使ってはいけない拡張仕様を使っていることになります。

life_span
質問者

お礼

大変分かりやすい解説ありがとうございます。 霧が晴れました。 MySQLしか扱ったことがなかったのですが、視野を広げて勉強してみます。 ありがとうございました。

その他の回答 (2)

  • moousi
  • ベストアンサー率70% (21/30)
回答No.3

なぜ、xとyに意図しない値が入るかというと、group byされた中で、一番最初の値を拾ってしまうからです。 なので、おっしゃる通り、期待する結果がクエリ1回で得られないということになります。 ここからはお節介です。 ソートして、一時テーブルあるいは一時格納専用に作ったテーブルへインサート。 その結果を提示されたSQLで表現することは可能です。(最後に、一時格納専用テーブルのtruncate) 可能ですが、「たまたま入った」nameを表示することになります。 提示されたSQL で抜いた結果セットから、商品名をidで検索した方が無難だと思います。

life_span
質問者

お礼

大変分かりやすい解説ありがとうございます。 やはり1回では無理なんですね。スッキリしました。 > 提示されたSQL で抜いた結果セットから、商品名をidで検索した方が無難だと思います。 この方法で勉強したいともいます。 アドバイスありがとうございました。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

まずはじめにサポートのきれたバージョンを使うということは自己責任です 大丈夫ですか? さて、この手の処理は「期待する結果がクエリ1回で得られない」です。 テンポラリを作ってやるのが普通です。 create temporary table temp_table select max(id) as id,group_id from hoge group by hoge.group_id; select temp_table.id,temp_table.group_id,hoge.name from temp_table inner join hoge using(id) order by hoge.id desc;

life_span
質問者

お礼

ご回答ありがとうございます。 1回では出来ないと聞いてスッキリしました。 また、例示もいただきましてありがとうございます。 あらためて勉強いたします。

関連するQ&A