この質問は、特定のケースで SQL ランキング機能を使用するかどうかについての議論から生じています。
一般的な RDBMS にはランキング機能が含まれています。つまり、クエリ言語にはTOP n ... ORDER BY key
、ROW_NUMBER() OVER (ORDER BY key)
、またはORDER BY key LIMIT n
( overview ) などの要素があります。
膨大な数のレコードから小さなチャンクのみを表示したい場合、パフォーマンスを向上させるのに非常に役立ちます。しかし、これらは大きな落とし穴ももたらします:key
が一意でない場合、結果は非決定論的です。次の例を検討してください。
users
user_id name
1 John
2 Paul
3 George
4 Ringo
logins
login_id user_id login_date
1 4 2009-08-17
2 1 2009-08-18
3 2 2009-08-19
4 3 2009-08-20
クエリは、最後にログインした人を返すことになっています:
SELECT TOP 1 users.*
FROM
logins JOIN
users ON logins.user_id = users.user_id
ORDER BY logins.login_date DESC
期待どおりGeorge
に返され、すべてが正常に見えます。しかし、新しいレコードがテーブルに挿入されlogins
ます:
1 4 2009-08-17
2 1 2009-08-18
3 2 2009-08-19
4 3 2009-08-20
5 4 2009-08-20
上記のクエリは何を返しますか? Ringo
? George
? わかりません。私が覚えている限り、たとえば MySQL 4.1 は、基準に一致する物理的に作成された最初のレコードを返します。つまり、結果はGeorge
. ただし、これはバージョンや DBMS によって異なる場合があります。何を返すべきだった?Ringo
彼が最後にログインしたようだからと言う人もいるかもしれませんが、これは純粋な解釈です。私の意見では、利用可能なデータから明確に判断することはできないため、両方が返されるべきでした。
したがって、このクエリは要件に一致します。
SELECT users.*
FROM
logins JOIN
users ON
logins.user_id = users.user_id AND
logins.login_date = (
SELECT max(logins.login_date)
FROM
logins JOIN
users ON logins.user_id = users.user_id)
別の方法として、一部の DBMS は特別な機能を提供します (たとえば、Microsoft SQL Server 2005 ではTOP n WITH TIES ... ORDER BY key
( gbnが推奨)、RANK
、およびDENSE_RANK
この目的のために を導入しています)。
たとえば、SO を検索ROW_NUMBER
すると、ランキング機能の使用を提案し、考えられる問題を指摘することを逃した多数のソリューションが見つかります。
質問: ランキング機能を含むソリューションが提案された場合、どのようなアドバイスが必要ですか?