2

記事の中でなぜアレル?、作者は問題を提起します:

ユーザーテーブルと写真テーブルがあり、すべてのユーザーデータとユーザーが作成した写真の*カウント*を選択するとします。

彼が提案した解決策(改行を追加)は次のとおりです。

SELECT users.*, photos_aggregation.cnt
FROM users
LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id)
  AS photos_aggregation
ON photos_aggregation.user_id = users.id

そのようなクエリを書こうとしたとき、私は思いついた

select users.*, if(count(photos.id) = 0, null, count(photos.id)) as cnt
from users
left join photos on photos.user_id = users.id
group by users.id

if()列リストのは、ユーザーが写真を持っていないときに同じように動作するようにするためのものです。)

記事の著者は続けて言います

これを書く方法を知っているのは高度なSQLプログラマーだけです(私は就職の面接でこの質問をよくしますが、誰もがそれを正しく理解しているのを見たことがありません)。そして、それは難しいことではありません!

私は自分自身を「高度なSQLプログラマー」とは考えていないので、微妙な何かが欠けていると思います。私は何が欠けていますか?

4

4 に答える 4

2

少なくとも一部のデータベースエンジンでは、お使いのバージョンでエラーが発生すると思います。MSSQLでは、selectはを生成し[Column Name] is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.ます。これは、groupbyまたはcountの値のみを選択できるためです。

バージョンをに変更するselect users.id, count(photo.id)と機能しますが、彼のクエリと同じ結果にはなりません。

実用的な解決策(または彼が思いついた特定の解決策)を考え出すために特に高度である必要はないとは言えませんが、joinまたは@ron tornambeが示唆するように、別のクエリでグループを実行する必要があります。

于 2012-09-28T20:59:11.763 に答える
1

ほとんどのDBMS(MySQLとPostgresは例外です)では、質問のバージョンは無効になります。

派生テーブルを使用しないクエリを次のように記述する必要があります。

select users.*, CASE WHEN count(photos.id) > 0 THEN count(photos.id) END as cnt
from users
left join photos on photos.user_id = users.id
group by users.id, users.name, users.email /* and so on*/

MySQLでは、リストにない集約されていないアイテムを選択できますgroup byが、これは、それらがの列に機能的に依存している場合にのみ安全ですgroup by

リストgroup byは派生テーブルがないとより冗長になりますが、ほとんどのオプティマイザーはとにかく一方を他方に変換できると思います。確かに、SQL Serverでは、PKと他のいくつかの列でグループ化されていることがわかった場合、それらの他の列の比較では実際にはグループ化されません。

このMySQLの動作と標準SQLの違いについては、GROUPBYの神話を暴くことにあります。

于 2012-09-28T21:00:44.677 に答える
0

別の方法として、相関サブクエリを作成することもできます。

SELECT u.*, (SELECT Count(*) FROM photos p WHERE p.userid=u.id) as cnt
FROM users u
于 2012-09-28T20:55:24.760 に答える
0

たぶん、記事の作者は間違っています。あなたの解決策も同様に機能し、それは非常に速いかもしれません。

個人的には、一緒にドロップしifます。0写真の数を数えたい場合は、「写真なし」ではなく「写真なし」になるのは理にかなっていnullます。

于 2012-09-28T20:37:24.973 に答える