这个问题源于关于在特定情况下是否使用 SQL 排名功能的讨论。
任何常见的 RDBMS 都包含一些排名功能,即它的查询语言具有像TOP n ... ORDER BY key
、ROW_NUMBER() OVER (ORDER BY key)
或ORDER BY key LIMIT n
(概览) 这样的元素。
如果您只想显示大量记录中的一小部分,它们在提高性能方面做得很好。但是它们也引入了一个主要的陷阱:如果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
您会发现许多建议使用排名功能的解决方案,而错过指出可能存在的问题。
问题:如果提出包含排名功能的解决方案,应该给出什么建议?