Этот вопрос возникает из обсуждения вопроса о том, использовать ли функцию ранжирования SQL или нет в particular case.Если функциональность ранжирования SQL следует рассматривать как «использовать с осторожностью»
Любая общая СУБД включает в себя некоторые функциональные возможности ранжирования, т.е. это язык запросов имеет элементы, такие как 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
. Но это может варьироваться от версии к версии и от СУБД до СУБД. Что нужно было вернуть? Можно сказать, 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)
В качестве альтернативы некоторой СУБД обеспечивает специальные функции (например, Microsoft SQL Server 2005 представляет TOP n WITH TIES ... ORDER BY key
(предложенный gbn), RANK
и DENSE_RANK
для этой цели).
Если вы ищете SO для, например, ROW_NUMBER
вы найдете множество решений, предлагающих использовать функции ранжирования и пропустить, чтобы указать на возможные проблемы.
Вопрос: Какой совет следует дать, если предлагается решение, включающее функции ранжирования?
+1. Отличный совет. – karlgrz