2017-11-14 3 views
1

例えば、bookpubデータベースは次の表(擬似コード)を含む:そのテーブルのプライマリキーだけでグループ化された場合、誤った結果を返す1つのテーブルの列を選択するクエリはありますか?

book (key: isbn) 
bookauthor (key:author_id, isbn) 
author (key: author_id) 

を次のクエリは、各著者の書籍の数を返す:

select lastname, firstname, count(isbn) 
from author 
join bookauthor using (author_id) 
group by lastname, firstname; 

ただし、次のクエリはまた、同じ生成します文句なしのMySQLの結果は:だから

select lastname, firstname, count(isbn) 
from author 
join bookauthor using (author_id) 
group by author_id; 

author_idはの代わりに使用すべきではない理由?

私は正式なSQLの仕様は、以下が含まれていることを追加される場合があります:

All non-aggregate groups in a SELECT expression list or HAVING expression list must be included in the GROUP BY clause. 

誰かがこれを解釈していただけますか? 「非集約グループ」とは何ですか? 「列」とだけ言わないのはなぜですか?さらに、「表現リスト」とは何ですか?この場合の式は常に列に評価されますか?

+2

信じていても、2人で同じ名前を共有することは可能です。したがって、author_idは常に使用する必要があります。 (デビットミッチェルと呼ばれる人が何本の本を書いているのか知りたいのでなければ、 – Strawberry

+0

ha ha ...私の隣室の学生は同じ名前で、私と同じイニシャルを持っていた。 –

+0

個人的には、ISBNは貧弱な鍵だと思います。大まかに言って、私はキーがデータベースの範囲を超えて現実世界で意味を持つべきではないと思います。 – Strawberry

答えて

0

group by句では、値が結果セットを分割するフィールドと式をリストします。これらのグループに対して、集計関数などを計算することができます。 MySQLでは、group by節には存在しない非集計式やフィールドを選択できますが、非標準SQLです。それらのフィールドにグループの複数の値がある場合、結果は非確定的になります。

プライマリキーでグループ化すると、キーごとに行が1つしかないため、結果は確定的になります。

3

SQLの実装はANSI定義に100%適合しません。いくつかのものが欠けている、いくつかのものが追加されている、何かが違うだけです。 GROUP BY句に含まれていなければならないSELECT式リストで

  • すべての非集計グループまたはHAVING式のリスト:MySQLの場合

    は、それはあなたが言及制限を強制しないように選ばれました。

これは、代わりに不格好の、あなたが気づいたGROUP BY primary_key構文を使用できます(そして実際に少しより高価な)GROUP BY property1, property2, property3, etc。清潔でエレガントです。

しかし、欠点があります。 MySQLのおかげで誤解や誤解がWeb開発者に多発しており、その柔軟性により、バグは検出されなくても滑ることができます。パフォーマンスの向上が最小限で、バグの可能性が大きいため、ほとんどの場合、回避することをお勧めします。

をすり抜けるバグの例は次のようになります。

SELECT 
    person.name, 
    address.city 
FROM 
    person 
INNER JOIN 
    address 
     ON address.person_id = person.id 
GROUP BY 
    person.id 

MySQLのだろう、かなり常には、そのコードを実行することができます。アドレステーブルが1人あたり複数のエントリを持つことができます(私は複数のアドレスに住んでいます)。

次のようにコードがおそらくあることを必要とすることができるが、MySQLはこれを強制することはありません:

SELECT 
    person.name, 
    address.move_in_date, 
    address.city 
FROM 
    person 
INNER JOIN 
    address 
     ON address.person_id = person.id 
GROUP BY 
    person.id, 
    address.id 

以上が関与して参加し、GROUP BYは、複数の主キー、または他のフィールドを含む必要があるより多くのチャンスを。

これは、MySQLがコードがあいまいであるときに返す値をMySQLが任意に選択することです。これは明示的に非決定論的です。次のコードは別のアドレスから1番地から都市と都市の人口を与えることができる: -/

SELECT 
    person.name, 
    address.move_in_date, 
    address.city, 
    city.population 
FROM 
    person 
INNER JOIN 
    address 
     ON address.person_id = person.id 
INNER JOIN 
    city 
     ON address.city_id = city.id 
GROUP BY 
    person.id 

人々は、次のような「トリック」でこれを悪用しようとする...

SELECT 
    person.name, 
    address.move_in_date, 
    address.city, 
    city.population 
FROM 
    person 
INNER JOIN 
    address 
     ON address.person_id = person.id 
INNER JOIN 
    city 
     ON address.city_id = city.id 
GROUP BY 
    person.id 
ORDER BY 
    person.id, 
    city.population DESC 

このは、人口が最も多い都市をMySQLエンジンに選択させるためにとなります。一人一人が住んでいた最も人口の多い都市を見つけるのに便利ですか?実際に動作することは保証されていません。まだ恣意的です。テーブルが書き込まれている、またはデータベースが分散環境にあるか、MySQLコードが変更された場合など、動作が変わる可能性があります。

しかし、とにかく人々はそれを行います。 「まあ、今まで私のために働いていたから」...

+0

良い答え。それはもちろん、複数のテーブルから列を選択するということから、私が求めていることではありません。それにもかかわらず、有益です。私はあなたの答えから、はい、プライマリキーまたは他のユニークな列(単数または複数)によるグループ分けが常に十分であることを暗示するかもしれないと思います。 –

+0

状況によって異なりますが、1つのフィールドが他のフィールドの他のコンポジットと同じようにユニークな場合は、はいです。 – MatBailie

+0

2つ以上のテーブルから列を選択することに私の疑問を外挿したいのであれば、 'group by 'の各テーブルの主キーを含むことが望ましい結果を生み出すかどうかを示すことができます。 –

関連する問題