sql >> データベース >  >> RDS >> Mysql

MySQLで適切にGROUPBYする方法は?

    最初に明確にすることは、SQLはMySQLではないということです。

    標準SQLでは、集約されていないフィールドのサブセットでグループ化することは許可されていません。理由は非常に単純です。このクエリを実行していると仮定します:

    SELECT color, owner_name, COUNT(*) FROM cars
    GROUP BY color
    

    そのクエリは意味がありません。説明しようとしても不可能です。確かにそれは色を選択し、色ごとの車の数を数えています。ただし、owner_nameも追加されています Whiteの場合のように、フィールドと特定の色の所有者が多数存在する可能性があります 色。したがって、owner_nameが多数存在する可能性がある場合 単一のcolorの値 これはたまたまGROUP BYの唯一のフィールドです 句...次に、どのowner_name 返されますか?

    owner_nameを返す必要がある場合 次に、ある種の基準を追加して、そのうちの1つだけを選択する必要があります。たとえば、アルファベット順の最初の基準は、この場合はJohnになります。 。その基準により、集計関数MIN(owner_name)が追加されます。 そして、少なくともselectステートメントのすべての非集計フィールドによってグループ化されるため、クエリは再び意味をなします。

    ご覧のとおり、標準SQLがグループ化に柔軟性を持たないことには明確で実用的な理由があります。そうでない場合は、列の値が予測できないという厄介な状況に直面する可能性があります。これは、特に実行中のクエリが銀行口座の取引を示している場合は、良い言葉ではありません。

    そうは言っても、なぜMySQLは意味をなさないかもしれないクエリを許可するのでしょうか?さらに悪いことに、上記のクエリのエラーは構文的に検出される可能性があります。簡単な答えは、パフォーマンスです。長い答えは、データの関係に基づいて、グループから予測できない値を取得すると、予測可能な値になる特定の状況があるということです。

    まだ理解していない場合、グループから予測できない要素を取得することで得られる値を予測できる唯一の方法は、グループ内のすべての要素が同じである場合です。この状況の明確な例は、まったく同じ質問のサンプルクエリにあります。 owner_idがどのようになっているのか見てみましょう およびowner_name 表に関連します。 owner_idが与えられた場合は明らかです 、例: 2 、1つの異なるowner_nameのみを持つことができます 。行数が多い場合でも、いずれかを選択すると、Mikeが得られます。 結果として。正式なデータベース用語では、これは owner_idとして説明できます。 owner_nameを機能的に決定します

    完全に機能するMySQLクエリを詳しく見てみましょう:

    SELECT owner_id, owner_name, COUNT(*) total FROM cars
    GROUP BY owner_id
    

    与えられたowner_id これは同じowner_nameを返します 、GROUP BYに追加します 句によって、それ以上の行が返されることはありません。集約された関数MAX(owner_name)を追加することもできます 返される行が少なくなることはありません。結果のデータはまったく同じになります。どちらの場合も、少なくともすべての非集計フィールドがグループ化されるため、クエリはすぐに正当な標準SQLクエリに変換されます。したがって、同じ結果を得るには3つのアプローチがあります。

    ただし、前述したように、この非標準のグループ化にはパフォーマンス上の利点があります。この過小評価されているリンク を確認できます。 これについては詳しく説明しますが、最も重要な部分を引用します:

    言及する価値のあることの1つは、結果が必ずしも間違っているというわけではないということです。 むしろ不確定 。言い換えれば、期待される結果が得られたからといって、正しいクエリを作成したとは限りません。適切なクエリを作成すると、常に期待どおりの結果が得られます。

    ご覧のとおり、このMySQL拡張機能をGROUP BYに適用する価値があるかもしれません。 句。とにかく、これがまだ100%明確でない場合は、グループ化が常に正しいことを確認する経験則があります。少なくとも、select句のすべての非集計フィールドで常にグループ化する 。特定の状況では数CPUサイクルを浪費している可能性がありますが、不確定を返すよりも優れています。 結果。それでも正しくグループ化できないことを恐れている場合は、 ONLY_FULL_GROUP_BY SQLモードは最後の手段になる可能性があります:)

    グループ化が正しく、パフォーマンスが高いように...または少なくとも正しいように。




    1. CDbCommand ::fetchColumn()が失敗しました:SQLSTATE [HY000]:一般エラー:2014他のバッファリングされていないクエリがアクティブな間はクエリを実行できません

    2. mysql SELECT * WHERE value =$ row ['item']

    3. oraclesqlの動的ピボット-手順

    4. sslとmysqlの統合-アクセスが拒否されました