ドキュメント用の表を以下に示します (簡略版はこちら)。
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-identifier
max-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 つの賢い動きをします。
- 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-group
forに 2 つの行がある場合group-identifier
、どちらの方法でも両方の行が結果に含まれます。
どちらのアプローチも SQL ANSI と互換性があるため、その「種類」に関係なく、お気に入りの RDBMS で動作します。
どちらのアプローチもパフォーマンスに優れていますが、結果は異なる場合があります (RDBMS、DB 構造、インデックスなど)。そのため、どちらかのアプローチを選択する場合は、ベンチマークを実施してください。そして、自分にとって最も適切なアプローチを選択してください。