SQL RANK () против ROW_NUMBER () - PullRequest
162 голосов
/ 13 октября 2011

Я смущен по поводу различий между ними.Запуск следующего SQL дает мне два идентичных набора результатов.Может кто-нибудь объяснить, пожалуйста, различия?

SELECT ID, [Description], RANK()       OVER(PARTITION BY StyleID ORDER BY ID) as 'Rank'      FROM SubStyle
SELECT ID, [Description], ROW_NUMBER() OVER(PARTITION BY StyleID ORDER BY ID) as 'RowNumber' FROM SubStyle

Ответы [ 7 ]

286 голосов
/ 13 октября 2011

Вы увидите разницу, только если у вас есть связи внутри раздела для определенного значения заказа.

RANK и DENSE_RANK в этом случае являются детерминированными, все строки с одинаковым значением для столбцов упорядочивания и разделения будут иметь одинаковый результат, тогда как ROW_NUMBER будет произвольно (недетерминированно) назначать приращение результат к связанным рядам.

Пример: (Все строки имеют одинаковый StyleID, поэтому находятся в одном и том же разделе, и в этом разделе первые 3 строки связаны, если упорядочены по ID)

WITH T(StyleID, ID)
     AS (SELECT 1,1 UNION ALL
         SELECT 1,1 UNION ALL
         SELECT 1,1 UNION ALL
         SELECT 1,2)
SELECT *,
       RANK() OVER(PARTITION BY StyleID ORDER BY ID)       AS 'RANK',
       ROW_NUMBER() OVER(PARTITION BY StyleID ORDER BY ID) AS 'ROW_NUMBER',
       DENSE_RANK() OVER(PARTITION BY StyleID ORDER BY ID) AS 'DENSE_RANK'
FROM   T  

Возвращает

StyleID     ID       RANK      ROW_NUMBER      DENSE_RANK
----------- -------- --------- --------------- ----------
1           1        1         1               1
1           1        1         2               1
1           1        1         3               1
1           2        4         4               2

Вы можете видеть, что для трех идентичных строк с шагом ROW_NUMBER значение RANK остается таким же, как и до 4. DENSE_RANK также присваивает один и тот же ранг всем трем строкам, но затем следующему отдельному значению присваивается значение 2.

195 голосов
/ 13 октября 2011

ROW_NUMBER: Возвращает уникальный номер для каждой строки, начинающейся с 1. Для строк, имеющих повторяющиеся значения, числа назначаются произвольно.

Ранг: Назначает уникальный номер для каждой строки, начинающейся с 1, за исключением строк, которые имеют повторяющиеся значения, в этом случае присваивается одинаковое ранжирование, и в последовательности для каждого дублирующего ранжирования появляется пробел.

28 голосов
/ 23 мая 2014

В этой статье рассматриваются интересные отношения между ROW_NUMBER() и DENSE_RANK() (функция RANK() специально не рассматривается).Когда вам нужно сгенерировать ROW_NUMBER() для оператора SELECT DISTINCT, ROW_NUMBER() будет выдавать различные значения до того, как они будут удалены ключевым словом DISTINCT.Например, этот запрос

SELECT DISTINCT
  v, 
  ROW_NUMBER() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number

... может дать такой результат (DISTINCT не имеет никакого эффекта):

+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a |          1 |
| a |          2 |
| a |          3 |
| b |          4 |
| c |          5 |
| c |          6 |
| d |          7 |
| e |          8 |
+---+------------+

Принимая во внимание, что этот запрос:

SELECT DISTINCT
  v, 
  DENSE_RANK() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number

... производит то, что вам, вероятно, нужно в этом случае:

+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a |          1 |
| b |          2 |
| c |          3 |
| d |          4 |
| e |          5 |
+---+------------+

Обратите внимание, что для предложения ORDER BY функции DENSE_RANK() потребуются все остальные столбцы из предложения SELECT DISTINCT для правильной работы.

Причина этого в том, что логически оконные функции вычисляются до применения DISTINCT .

Все три функции для сравнения

Использование PostgreSQL /Стандартный синтаксис Sybase / SQL (предложение WINDOW):

SELECT
  v,
  ROW_NUMBER() OVER (window) row_number,
  RANK()       OVER (window) rank,
  DENSE_RANK() OVER (window) dense_rank
FROM t
WINDOW window AS (ORDER BY v)
ORDER BY v

... вы получите:

+---+------------+------+------------+
| V | ROW_NUMBER | RANK | DENSE_RANK |
+---+------------+------+------------+
| a |          1 |    1 |          1 |
| a |          2 |    1 |          1 |
| a |          3 |    1 |          1 |
| b |          4 |    4 |          2 |
| c |          5 |    5 |          3 |
| c |          6 |    5 |          3 |
| d |          7 |    7 |          4 |
| e |          8 |    8 |          5 |
+---+------------+------+------------+
3 голосов
/ 13 октября 2011

Совсем немного:

Ранг строки равен единице плюс количество рангов, предшествующих рассматриваемому ряду.

Row_number - это отчетливый ранг строк без пробела в рейтинге.

http://www.bidn.com/blogs/marcoadf/bidn-blog/379/ranking-functions-row_number-vs-rank-vs-dense_rank-vs-ntile

0 голосов
/ 23 июня 2015

Я ничего не сделал с рангом, но я обнаружил это сегодня с row_number ().

select item, name, sold, row_number() over(partition by item order by sold) as row from table_name

Это приведет к появлению повторяющихся номеров строк, поскольку в моем случае каждое имя содержит все элементы. Каждый товар будет заказан по количеству проданных товаров.

+--------+------+-----+----+
|glasses |store1|  30 | 1  |
|glasses |store2|  35 | 2  |
|glasses |store3|  40 | 3  |
|shoes   |store2|  10 | 1  |
|shoes   |store1|  20 | 2  |
|shoes   |store3|  22 | 3  |
+--------+------+-----+----+
0 голосов
/ 26 декабря 2014

Также обращайте внимание на ORDER BY в PARTITION (например, используется стандартная база данных AdventureWorks) при использовании RANK.

SELECT as1.SalesOrderID, as1.SalesOrderDetailID, RANK () OVER (PARTITION BYas1.SalesOrderID ORDER BY as1.SalesOrderID) ranknoequal, RANK () OVER (PARTITION BY as1.SalesOrderID ORDER BY as1.SalesOrderDetailId) ranknodiff FROM Sales.SalesOrderDetail as1 ГДЕ SalesOrder * 100 * * 100 * * ORDДает результат:

SalesOrderID SalesOrderDetailID rank_same_as_partition rank_salesorderdetailid43659 1 1 143659 2 1 243659 3 1 343659 4 1 443659 5 1 543659 6 1 643659 7 1 743659 8 1 843659 9 1 943659 10 1 1043659 11 1 1143659 12 1 12

Но если изменить порядок на (использовать OrderQty:

ВЫБРАТЬ as1.SalesOrderID, as1.OrderQty, RANK () OVER (PARTITION BY as1.SalesOrderID ORDER BY as1.SalesOrderID) ranknoequal, RANK() OVER (PARTITION BY as1.SalesOrderID ORDER BY as1.OrderQty) rank_orderqty FROM Sales.SalesOrderDetail as1 WHERE SalesOrderId = 43659 ORDER BY OrderQty;

Дает43659 1 1 143659 1 1 143659 1 1 143659 1 1 143659 1 1 143659 1 1 143659 2 1 743659 2 1 743659 3 1 943659 3 1 943659 4 1 1143659 6 1 12

Обратите внимание, как изменяется ранг, когда мы используем OrderQty (вторая таблица правого столбца) в ORDER BY, и как он изменяется, когда мы используем SalesOrderDetailID (первая таблица правого столбца) в ORDER BY.

0 голосов
/ 12 декабря 2014

Посмотрите этот пример.

CREATE TABLE [dbo].#TestTable(
    [id] [int] NOT NULL,
    [create_date] [date] NOT NULL,
    [info1] [varchar](50) NOT NULL,
    [info2] [varchar](50) NOT NULL,
)

Вставьте некоторые данные

INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (1, '1/1/09', 'Blue', 'Green')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (1, '1/2/09', 'Red', 'Yellow')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (1, '1/3/09', 'Orange', 'Purple')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (2, '1/1/09', 'Yellow', 'Blue')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (2, '1/5/09', 'Blue', 'Orange')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (3, '1/2/09', 'Green', 'Purple')
INSERT INTO dbo.#TestTable (id, create_date, info1, info2)
VALUES (3, '1/8/09', 'Red', 'Blue')

Повторите те же значения для 1

INSERT INTO dbo. # TestTable (id, create_date, info1, info2) VALUES (1, '1/1/09', 'Blue', 'Green')

Просмотреть все

SELECT * FROM #TestTable

Посмотреть результаты

SELECT Id,
    create_date,
    info1,
    info2,
    ROW_NUMBER() OVER (PARTITION BY Id ORDER BY create_date DESC) AS RowId,
    RANK() OVER(PARTITION BY Id ORDER BY create_date DESC)    AS [RANK]
FROM #TestTable

Нужно понимать другое

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...