質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

MySQLのSELECTでのGROUP BY句について

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 2,995

papi_tokei

score 106

前提・実現したいこと

MySQLを勉強しているのですが,少し疑問に思った部分があったので,
疑問を解決したいです.

使用しているデータ

<都道府県テーブル>
都道府県コード
都道府県名
人口
面積

<市町村テーブル>
都道府県コード
市町村コード
区分
市町村名
人口
面積
世帯数

該当のソースコード

以下のSQLは市町村数が上位10個の都道府県を表示するためのものです.
適切に動作し,出力結果も正しいです.
ですが,私の認識では,GROUP BYで指定したものか,集約関数しかSELECTのカラムに選択出来ないと思っていました.
しかし,今回はGROUP BYに都道府県コードを設定し,SELECTには都道府県名を指定しています.

SELECT 都道府県名, COUNT(*) AS 市町村数 FROM 都道府県 JOIN 市町村 USING (都道府県コード) GROUP BY 都道府県コード ORDER BY 市町村数 DESC LIMIT 10;

以下のように,GROUP BYの部分を都道府県名に変更しても.同じ結果が出力されます.
エラーも出ません.

SELECT 都道府県名, COUNT(*) AS 市町村数 FROM 都道府県 JOIN 市町村 USING (都道府県コード) GROUP BY 都道府県名 ORDER BY 市町村数 DESC LIMIT 10;

解決したい問題

確かに,都道府県コードと都道府県名は一対一対応なので,取替え可能ですが,
そういう話でもないような気がします.
GROUP BYに指定したもの意外をSELECTに設定できている疑問を解決したいです.

よろしくお願いします.

補足情報(言語/FW/ツール等のバージョンなど)

DockerでMySQLを実行しています.

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+8

MySQLの場合、集計しない列を取ってくると、どれか1個を適当に取ってきます(マニュアル)。

ただし、これは標準SQLでは書けないものですので、「値が1つ」とわかっていても、MAX(都道府県名)のような集計関数を挟むのが、より良いやり方です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/17 18:37

    迅速な回答ありがとうございます.
    GROUP BYに設定していないものを取ると,値が不定になるのですね.
    その場合は,MAXなどの集約関数を使えば良いということ,勉強になりました.
    ベストアンサーは最初に回答いただいた方とさせていただきました.

    キャンセル

+6

標準SQLであればご認識の通りです。この機能はMySQL拡張です。

12.19.3 MySQL での GROUP BY の処理

MySQL では、選択リストが GROUP BY 句で名前が指定されていない非集約カラムを参照できないように、GROUP BY の使用が拡張されています。つまり、上記のクエリーは MySQL では正当です。この機能を使用すると、不要なカラムのソートおよびグループ化が回避されるため、パフォーマンスを改善できます。

結果の整合性は保証されないようです。

ただし、これは主に、GROUP BY で名前が指定されていない各非集約カラム内のすべての値がグループごとに同じである場合に役立ちます。サーバーは各グループから任意の値を自由に選択できるため、同じ値でなければ、選択した値は不確定です。さらに、ORDER BY 句を追加しても、各グループからの値の選択が影響を受ける可能性はありません。値が選択されたあとに結果セットのソートが発生しますが、ORDER BY によって、サーバーで選択された各グループ内の値は影響を受けません。

無効にすることもできるようです。

MySQL GROUP BY の拡張を無効にするには、ONLY_FULL_GROUP_BY SQL モードを有効にします。これにより、標準 SQL の動作が有効になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/17 18:41

    非常に詳しく回答いただきありがとうございます.
    GROUP BYの拡張を無効にも出来るのですね.
    MySQLも奥が深く難しいですが,地道に勉強していこうと思います.

    キャンセル

checkベストアンサー

+5

GROUP BYで指定したものか,集約関数しかSELECTのカラムに選択出来ない

標準SQLとしてはこの認識で問題ないと思います。

少しリファレンスなどを見た感じでは、MySQLのGROUP BYは標準SQLを拡張した仕様らしく、GROUP BYで指定されていないカラムもSELECTで使用できるようです。
ただし、集約される行にあるどの値が返ってくるかが不確定みたいです。

参照:リファレンス
※日本語版は文がちょっと変ですが、英語版の方も合わせてみてもらえればと思います。

今回のケースでは、「都道府県コードと都道府県名は一対一対応」となっているため確実に想定している値が出ているだけ、という状況なのでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/17 18:35

    迅速な回答をありがとうございます.
    MySQLは標準SQLを拡張したつくりになっているのですね.
    別のSQLを試すと,「SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.都道府県.都道府県コード' which is not functionally dependent on columns in GROUP BY clause;」といったエラーが出たので,疑問に思って質問させていただきました.

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る