2009-06-21 5 views
35

することで、グループ内の列ではないの選択、私は既存のアプリケーションに機能を追加しようとしていると私は、MySQLのビュー間でこのような何か来た:いくつかの集約関数がありますので、のMySQL -

SELECT 
    AVG(table_name.col1), 
    AVG(table_name.col2), 
    AVG(table_name.col3), 
    table_name.personID, 
    table_name.col4 
FROM table_name 
GROUP BY table_name.personID; 

OKを。あなたがグループ化しているので、personIDを選択することができます。しかし、集計関数にはなく、GROUP BY句の一部ではない列も選択しています。これはどのように可能ですか?値はグループごとに一意ではないので、ランダムな値を選択するだけですか?

どこから来たのですか(MSSQL Server)、これはエラーです。誰かがこの動作を私に説明し、MySQLでなぜ許可されているのですか?

答えて

40

この機能はあいまいなクエリを許可し、その列から選択された任意の値を含む結果セットを暗黙に返します。実際には、最初に物理的に格納されているグループ内の行からの値になる傾向があります。

GROUP BY条件の列に機能的に依存する列のみを選択した場合、これらのクエリはあいまいではありません。つまり、グループを定義する値ごとに「あいまいな」列の異なる値が1つしかない場合は、問題はありません。このクエリは、それが論理的に曖昧になることができないにもかかわらず、Microsoft SQL Serverの(およびANSI SQL)で違法になります:

また
SELECT AVG(table1.col1), table1.personID, persons.col4 
FROM table1 JOIN persons ON (table1.personID = persons.id) 
GROUP BY table1.personID; 

、MySQLはそれが標準ごとに動作させるためにSQLモードがあります:ONLY_FULL_GROUP_BY

FWIWの場合、SQLiteではあいまいなGROUP BY句も許可しますが、グループ内のの最後の行から値を選択します。少なくとも私がテストしたバージョンで†


であることを意味するものは、任意のです。将来、MySQLまたはSQLiteのいずれかの実装が変更され、いくつかの動作が異なる可能性があります。したがって、このようなあいまいな状況に陥っているような行動には依存しないようにすべきです。決定的で曖昧でないようにクエリを書き直す方が良いです。そのため、MySQL 5.7ではデフォルトでONLY_FULL_GROUP_BYが有効になりました。

+3

これは完全に真実ではないと私は言いたいと思います。 ANSI SQL-99では、選択されたフィールドは集計でなければならず、機能はgroup by句に依存します。 user_idでグループ化するときにuser_nameを選択するのはまったく問題ありません。 SQL ServerとOracleは、これに準拠していません。user_idのみがgroup byリストにあるときにuser_nameを選択できないためです。選択された各列が実際に機能的にuser_idに依存しているかどうかをチェックしないため、MySQLは準拠しません。 –

+0

@ThorstenKettner、ありがとう、あなたは正しいです。 MySQL 5.7が改良されました。この場合はANSI SQLをサポートする方がはるかに賢明です。 –

9

私はグーグルでちょっと待ってください... my answerのようです。

MySQLは GROUP BY句に表示されていないSELECTリスト に非集約列 や計算を使用することができますので、 BY GROUPの使用を拡張します。この機能を使用すると、 不要な列の並べ替えと のグループ化を回避して、より良いパフォーマンスを得ることができます。たとえば、あなたが標準SQLでクエリ

次 でcustomer.nameでグループに を必要としない、あなたは、GROUP BY句に customer.nameを追加する必要があります。 MySQLでは、名前は冗長です。

まだ、それは間違っているようです。

+3

あなたは間違っているようです。それは!上記のBill Karwinが指摘しているように、いくつかの例外があると確信していますが、データを十分に理解していない開発者や、この機能が実際にどのように機能しているのか、不適切なgroup by節悪い結果を得ることがあります。この機能はデフォルトではオフにしておく必要があり、エンジニアに十分に通知されている場合には、クエリオプションで意図的に無効にする必要があります。 –

+0

'SELECT * FROM table1'を指定して一貫した順序で結果を返すのは、間違ったことではなく、バグではなく機能です。 – kmoser

-1
select * from personel where p_id IN(select 
min(dbo.personel.p_id) 
FROM 
personel 
GROUP BY dbo.personel.p_adi) 
+1

これは間違いなく質問 – Ojen

+0

@Ojenには答えていませんが、何が起きているのかを説明しています。上のコードは、この非標準的な動作を標準SQLを使ってどのようにモデル化できるかの例です。 – Griddo