SQLは列の最大値を持つ行のみを選択します [重複] 質問する

SQLは列の最大値を持つ行のみを選択します [重複] 質問する

ドキュメント用の表を以下に示します (簡略版はこちら)。

id 回転 コンテンツ
1 1 ...
2 1 ...
1 2 ...
1 3 ...

ID ごとに 1 行を選択し、最も高い rev のみを選択するにはどうすればよいでしょうか。
上記のデータでは、結果には と の 2 つの行が含まれるはずです。[1, 3, ...][2, 1, ..]MySQLを使用しています。

現在、ループ内のチェックを使用して、結果セットから古い rev を検出して上書きしています。 しかし、これが結果を達成する唯一の方法でしょうか? SQLwhileソリューションはないのでしょうか?

ベストアンサー1

一目見ただけで...

必要なのは、集計関数GROUP BYを含む句だけですMAX

SELECT id, MAX(rev)
FROM YourTable
GROUP BY id

それは決してそんなに単純なことではないですよね?

content列も必要だと気づきました。

これは SQL で非常によく聞かれる質問です。あるグループ識別子ごとに、ある列の最大値を持つ行のデータ全体を見つけます。私は仕事中にこの質問を何度も聞きました。実際、これは現在の仕事の技術面接で私が答えた質問の 1 つでした。

実際、このような質問は非常によくあるため、Stack Overflow コミュニティでは、このような質問に対処するためだけに 1 つのタグを作成しました。

基本的に、この問題を解決するには 2 つのアプローチがあります。

group-identifier, max-value-in-groupシンプルなサブクエリによる結合

このアプローチでは、まずサブクエリで (すでに上で解決済み) を見つけます。次に、group-identifier, max-value-in-groupの両方が等価になるように、テーブルをサブクエリに結合しますgroup-identifiermax-value-in-group

SELECT a.id, a.rev, a.contents
FROM YourTable a
INNER JOIN (
    SELECT id, MAX(rev) rev
    FROM YourTable
    GROUP BY id
) b ON a.id = b.id AND a.rev = b.rev

左 自分自身と結合し、結合条件とフィルターを調整する

このアプローチでは、テーブルをそれ自体と左結合します。等価性は に入りますgroup-identifier。次に、2 つの賢い動きをします。

  1. 2番目の結合条件は、左側の値が右側の値より小さいことです。
  2. ステップ 1 を実行すると、実際に最大値を持つ行のNULL右側には が含まれます ( ですLEFT JOIN、覚えていますか?)。次に、結合された結果をフィルタリングして、右側が である行のみを表示しますNULL

結局、次のようになります。

SELECT a.*
FROM YourTable a
LEFT OUTER JOIN YourTable b
    ON a.id = b.id AND a.rev < b.rev
WHERE b.id IS NULL;

結論

どちらのアプローチもまったく同じ結果をもたらします。

max-value-in-groupforに 2 つの行がある場合group-identifier、どちらの方法でも両方の行が結果に含まれます。

どちらのアプローチも SQL ANSI と互換性があるため、その「種類」に関係なく、お気に入りの RDBMS で動作します。

どちらのアプローチもパフォーマンスに優れていますが、結果は異なる場合があります (RDBMS、DB 構造、インデックスなど)。そのため、どちらかのアプローチを選択する場合は、ベンチマークを実施してください。そして、自分にとって最も適切なアプローチを選択してください。

おすすめ記事