SQL RANK () 대 ROW_NUMBER ()


190

나는 이들의 차이점에 대해 혼란스러워합니다. 다음 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

답변:


222

ROW_NUMBER : 1로 시작하는 각 행의 고유 번호를 반환합니다 . 값이 중복되는 행의 경우 임의로 숫자가 할당됩니다.

순위 : 중복 값이있는 행을 제외하고 1로 시작하는 각 행에 고유 번호를 할당합니다.이 경우 동일한 순위가 할당되고 각 중복 순위의 시퀀스에 간격이 나타납니다.


327

파티션 내에서 특정 순서 값과의 관계가있는 경우에만 차이점을 볼 수 있습니다.

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가 할당됩니다.


26
Great! ... DENSE_RANK에 대해 언급 해 주셔서 감사합니다
Sandeep Thomas

7
좋은 예를 주셔서 감사합니다. ROW_NUMBER ()가 훨씬 더 적합했을 때 RANK () 함수를 잘못 사용하고 있음을 깨달았습니다.
Ales Potocnik Hahonina

2
진지하게, 이것은 굉장하다.
매트 펠 자니

35

이 문서 간의 흥미로운 관계 커버 ROW_NUMBER()DENSE_RANK() 합니다 ( RANK()함수 특별히 처리하지 않음). 당신이 생성 필요로 할 때 ROW_NUMBER()A의 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 |
+---+------------+------+------------+

1
ROW_NUMBER와 DENSE_RANK는 구별이 적용되기 전에 값을 생성합니다. 실제로 모든 순위 함수 또는 함수는 DISTINCT가 적용되기 전에 결과를 생성합니다.
Thanasis Ioannidis 2018 년

1
@ThanasisIoannidis : 물론입니다. 블로그 게시물에 대한 링크로 답변을 업데이트했습니다. 여기 에서 SQL 작업
Lukas Eder


1

파티션 절이없는 간단한 쿼리 :

select 
    sal, 
    RANK() over(order by sal desc) as Rank,
    DENSE_RANK() over(order by sal desc) as DenseRank,
    ROW_NUMBER() over(order by sal desc) as RowNumber
from employee 

산출:

    --------|-------|-----------|----------
    sal     |Rank   |DenseRank  |RowNumber
    --------|-------|-----------|----------
    5000    |1      |1          |1
    3000    |2      |2          |2
    3000    |2      |2          |3
    2975    |4      |3          |4
    2850    |5      |4          |5
    --------|-------|-----------|----------

0

이 예를보십시오.

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에 대해 동일한 값을 반복

dbo. # TestTable에 삽입 (ID, create_date, info1, info2) 값 (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

다른 이해가 필요


-1

또한 RANK를 사용할 때 PARTITION (예 : Standard AdventureWorks db가 사용됨)의 ORDER BY에주의하십시오.

선택 as1.SalesOrderID, as1.SalesOrderDetailID, RANK () OVER (PARTITION BY as1.SalesOrderID ORDER BY as1.SalesOrderID) ranknoequal, RANK () OVER (PARTITION BY as1.SalesOrderID ORDER BY as1.SalesOrderDetailedDetailedDetailedDetailedDetailedDetailedDetailedDetaildDetailedDetaildDetaildDetailedDetaildDetailedDetaildDetailedDetaildDetailedDetailedDetailedDetailedDetaildder.com SalesOrderId = 43659 ORDER BY SalesOrderDetailId;

결과를 제공합니다 :

SalesOrderID SalesOrderDetailID rank_same_as_partition rank_salesorderdetailid
43659 1 1
43659 2 1
43 43 1 3
43659 4 1 4
43,659 5 1 5
43659 6 1 6
43659 7 1 7
43659 8 1 8
43659 9 1394
43659 10 110
43,659 111 11
43,659 12 1 12

그러나 주문을로 변경하면 (OrderQty 사용 :

select 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 FROMEHERE.Orderqty FROME.Des.OrderQty FROME.Des.OrderQty FROMS.Des.OrderQty FROMS.Des.OrderQty FROMS.Detail. SalesOrderId = 43659 주문자 주문 수량;

제공합니다 :

SalesOrderID에 OrderQty rank_salesorderid rank_orderqty
43,659 1 1 1
43659 1 1 1
43659 1 1 1
43659 1 1 1
43659 1 1 1
43659 1 1 1
43659 2 1 7
43659 2 1 7
43659 3 1394
43659 3 1394
43659 4 11 1
43,659 6 1 12

ORDER BY에서 OrderQty (가장 오른쪽 열의 두 번째 테이블)를 사용할 때 순위가 어떻게 변경되고 ORDER BY에서 SalesOrderDetailID (가장 오른쪽 열의 첫 번째 테이블)를 사용할 때 순위가 어떻게 변하는 지 확인하십시오.


-1

나는 순위로 아무것도하지 않았지만 오늘 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  |
+--------+------+-----+----+
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.