Where 절의 SQL Row_Number () 함수


90

Row_Number()where 절의 함수로 답한 질문이 하나 있습니다. 하나의 쿼리를 시도했을 때 다음 오류가 발생했습니다.

"Msg 4108, 수준 15, 상태 1, 줄 1 창 함수는 SELECT 또는 ORDER BY 절에만 나타날 수 있습니다."

내가 시도한 쿼리는 다음과 같습니다. 이 문제를 해결하는 방법을 아는 사람이 있으면 알려주세요.

SELECT employee_id 
FROM V_EMPLOYEE 
WHERE row_number() OVER ( ORDER BY employee_id ) > 0 
ORDER BY Employee_ID

9
ROW_NUMBER() OVER (ORDER BY employee_id) > 0항상 평가됩니다TRUE
Quassnoi

3
네, 맞습니다. 나는 언제든지 바꿀 수있는 상태에 대해 걱정하지 않습니다. 먼저 쿼리가 작동하고 행 번호를 500에서 800 사이로 유지하려고 생각합니다. 감사합니다

2
@Joseph : 왜 CTE를 사용하지 않으려 고합니까?
OMG Ponies

1
@rexem-저는 SQL Server 전문가가 아닙니다. 성능과 관련된 많은 문제에 직면 한 대규모 프로젝트에서 팀을 돕고 있습니다. 그들은 UDF와 CTE를 사용하고 있습니다. 테이블 중 하나에는 5000 개의 레코드 만 있으며 5 명의 사용자가 검색에 액세스하는 경우 검색하는 데 1 분 이상 걸립니다. 언젠가 실패하고 시간이 초과됩니다. 그래서 저는 CTE와 UDF를 피하고 성능 문제를 해결할 수있는 간단한 SQL 쿼리를 만들려고 노력하고 있습니다.

1
안녕하세요, row_number ()를 사용하여 다른 방식으로 답변하는 아래 게시 한 링크를 참조하십시오. 누군가 내 초기 쿼리를 링크의 쿼리와 비교할 수 있습니까? 도움을 주셔서 감사합니다.

답변:


91

이 문제를 해결하려면 CTE에 select 문을 래핑 한 다음 CTE에 대해 쿼리하고 where 절에서 창 함수의 결과를 사용할 수 있습니다.

WITH MyCte AS 
(
    select   employee_id,
             RowNum = row_number() OVER ( order by employee_id )
    from     V_EMPLOYEE 
    ORDER BY Employee_ID
)
SELECT  employee_id
FROM    MyCte
WHERE   RowNum > 0

7
CTE를 피하려고합니다. 내가 찾고있는 최악의 경우입니다. 감사합니다

3
CTE 대신 하위 쿼리를 사용하면 더 빨리 실행될 수 있습니다. 어떤 경우에는 1.5 배 더 나은 성능을 보았습니다
Brian Webster

3
CTE SELECT에도 TOP이 있어야합니다. 그렇지 않으면 SQL 2008 Server가 ORDER BY (TOP를 사용하지 않는 한 지원되지 않음)로 인해 쿼리를 실행하지 않습니다.
Muflix

2
SQL2005 (ugh)를 사용하고 있습니다. FROM 뒤에 "ORDER BY"를 삭제하면 "TOP"사용을 피할 수 있습니다. 어쨌든 OVER 이후에 (Order By)와 중복됩니다.
조 B

나는 CTE없이 ROW_NUMBER()in WHERE절 을 사용하는 방법이 있기 를 바랬다 :(
Jalal

61
SELECT  employee_id
FROM    (
        SELECT  employee_id, ROW_NUMBER() OVER (ORDER BY employee_id) AS rn
        FROM    V_EMPLOYEE
        ) q
WHERE   rn > 0
ORDER BY
        Employee_ID

이 필터는 중복 ROW_NUMBER()됩니다.에서 시작 1하고 항상보다 큽니다 0.


2
@ DavideChicco.it : SQL Server에서 파생 테이블에는 별칭이 필요합니다 ( AS q대신 작성 했어야 하지만이 방법도 작동합니다).
Quassnoi

2
가독성은 별칭 이름을 지정할 때 중점을 둡니다. rn을 RowNumber로, q를 DerivedTable로, where 절을 DerivedTable.RowNumber> 0으로 작성할 수 있습니다. 제 생각에는 코드가 마음에 새지 않은 6 개월 후에는 훨씬 덜 혼란 스러울 것입니다.
에드워드 꼬모

2
@EdwardComeau : 요즘 rn보편적으로 통용되는 행 번호의 약어입니다. Google 검색 문자열에 "row_number over as ..."를 입력하고 제안하는 내용을 확인하십시오.
Quassnoi 2016 년

3
@Quassnoi, 가독성은 좋은 코딩의 핵심이며 rn (또는 기타 축약 된 별칭)을 번역하는인지 적 노력은 귀하와 귀하의 코드를 유지하는 사람들에게 더해집니다. NB, Microsoft 첫 번째 히트, SELECT ROW_NUMBER () OVER (ORDER BY SalesYTD DESC) AS Row, ... 또한 이전에 rn을 본 적이 없으므로 "유니버설"에서의 마일리지가 다를 수 있습니다.
Edward Comeau 2016 년

1
@Quassnoi, 초 히트, SO 기사 - stackoverflow.com/questions/961007/how-do-i-use-row-number 여러 변화 및 RN하지 ;-)
에드워드 꼬모

32
Select * from 
(
    Select ROW_NUMBER() OVER ( order by Id) as 'Row_Number', * 
    from tbl_Contact_Us
) as tbl
Where tbl.Row_Number = 5

19

나는 당신이 다음과 같은 것을 원한다고 생각합니다.

SELECT employee_id 
FROM  (SELECT employee_id, row_number() 
       OVER (order by employee_id) AS 'rownumber' 
       FROM V_EMPLOYEE) TableExpressionsMustHaveAnAliasForDumbReasons
WHERE rownumber > 0

4
위 쿼리가 작동하지 않는 경우 테이블에 대한 별칭을 만듭니다. From V_EMPLOYEE) AA를 별칭으로 추가하는 두 번째 마지막 줄을 수정 합니다.
Hammad Khan 2014

7

rexem의 답변에 대한 의견에 대한 응답으로 인라인 뷰 또는 CTE가 더 빠를 지 여부와 관련하여 쿼리를 다시 캐스팅하여 테이블 I 및 모든 사람이 사용할 수있는 sys.objects를 사용했습니다.

WITH object_rows AS (
    SELECT object_id, 
        ROW_NUMBER() OVER ( ORDER BY object_id) RN
    FROM sys.objects)
SELECT object_id
FROM object_rows
WHERE RN > 1

SELECT object_id
FROM (SELECT object_id, 
        ROW_NUMBER() OVER ( ORDER BY object_id) RN
    FROM sys.objects) T
WHERE RN > 1

생성 된 쿼리 계획은 정확히 동일했습니다. 나는 모든 경우에 쿼리 최적화 프로그램이 최소한 CTE를 인라인보기로 간단히 교체하거나 그 반대의 경우 동일한 계획을 제시 할 것이라고 예상합니다.

물론, 자신의 시스템에서 자신의 쿼리를 시도하여 차이가 있는지 확인하십시오.

또한 row_number()where 절은 Stack Overflow에 주어진 답변의 일반적인 오류입니다. Logicaly row_number()는 select 절이 처리 될 때까지 사용할 수 없습니다. 사람들은 그것을 잊고 답을 시험하지 않고 답할 때 때로 답이 틀립니다. (내가 죄를 지은 혐의.)


1
Thx Shannon. 사용중인 SQL Server 버전은 무엇입니까?
OMG Ponies

1
그렇다면 해당 링크에 제공된 답변이 잘못 되었습니까? 하지만 질문을 올린 사람은 그게 효과가 있다는 것에 동의했습니다 .. 놀라워요 .. :-)

2
@Joseph, 그러나 링크 된 질문에서 OP가 게시 한 다른 답변을 보면 그가 수락 된 답변과 동일하지 않은 코드 버전에 연결되어 있음을 알 수 있습니다. 입력 한대로 실행되지 않더라도 그가 대답을 수락 한 이유를 모르겠습니다. 받아 들여진 후 어느 시점에서 편집되었을 수도 있고, 완전히 정확하지 않더라도 그를 데려 가기에 충분했을 수도 있습니다.
Shannon Severance

1
@Rexem : SQL Server 2005 및 SQL Server 2008 둘 다. 이전 버전은 CTE 또는 ROW_NUMBER ()를 지원하지 않습니다
Shannon Severance

6

나는 CTE 또는 Sub Query의 사용을 보여주는 모든 답변이 이것에 대한 충분한 수정이라고 생각하지만 OP에 문제가있는 이유에 대해 아무도 이해하지 못합니다. OP 제안이 작동하지 않는 이유는 다음과 같은 논리 쿼리 처리 순서 때문입니다.

  1. 에서
  2. 의 위에
  3. 붙다
  4. 어디
  5. 그룹화
  6. CUBE / ROLLUP 포함
  7. HAVING
  8. 고르다
  9. 뚜렷한
  10. 주문
  11. 상단
  12. 오프셋 / 패치

나는 이것이 이와 같은 문제가 발생하는 이유를 설명하기 때문에 대답에 크게 기여한다고 생각합니다. 많은 기능에 필요한 CTE 또는 하위 쿼리 WHERESELECT만들기 전에 항상 처리 됩니다. SQL Server에서 많이 볼 수 있습니다.


4

CTE 사용 (SQL Server 2005+) :

WITH employee_rows AS (
  SELECT t.employee_id,
         ROW_NUMBER() OVER ( ORDER BY t.employee_id ) 'rownum'
    FROM V_EMPLOYEE t)
SELECT er.employee_id
  FROM employee_rows er
 WHERE er.rownum > 1

인라인보기 / 비 CTE 동등 대안 사용 :

SELECT er.employee_id
  FROM (SELECT t.employee_id,
               ROW_NUMBER() OVER ( ORDER BY t.employee_id ) 'rownum'
          FROM V_EMPLOYEE t) er
 WHERE er.rownum > 1

1
어느 것이 성능이 더 좋습니까? CTE 또는 하위 쿼리를 사용하십니까? 감사합니다

1
Shannon의 대답을 참조하십시오-그의 테스트에서 그들은 동등합니다.
OMG Ponies

6
아니, 빠르지 않습니다. 이어 SQL Server, CTE의 인라인 뷰는 같은 일을하고 동일한 성능을 가지고있다. 비 결정적 함수가에서 사용되면 CTE각 호출에서 다시 평가됩니다. 하나는 더티 트릭을 사용하여 CTE. 내 블로그에이 문서를 참조하십시오 explainextended.com/2009/07/28/... explainextended.com/2009/05/28/generating-xml-in-subqueries을
Quassnoi

2

질문에 대한 OP의 답변을 기반으로 :

이 링크를 참조하십시오. 질문을 한 사람을 위해 작동하는 다른 솔루션이 있습니다. 나는 이와 같은 해결책을 찾으려고 노력하고 있습니다.

SQL Server 2005에서 ROW_NUMBER () OVER ()를 사용하여 다른 열에 정렬을 사용하는 페이지가 매겨진 쿼리

~ 조셉

"방법 1"은 연결된 질문의 OP 쿼리와 같고 "방법 2"는 선택한 답변의 쿼리와 같습니다. 이에 링크 된 코드를 볼 수밖에 없었 선택한 답변에 코드가 작동하도록 수정 된 이후, 정말 무슨 일이 있었는지 확인합니다. 이 시도:

DECLARE @YourTable table (RowID int not null primary key identity, Value1 int, Value2 int, value3 int)
SET NOCOUNT ON
INSERT INTO @YourTable VALUES (1,1,1)
INSERT INTO @YourTable VALUES (1,1,2)
INSERT INTO @YourTable VALUES (1,1,3)
INSERT INTO @YourTable VALUES (1,2,1)
INSERT INTO @YourTable VALUES (1,2,2)
INSERT INTO @YourTable VALUES (1,2,3)
INSERT INTO @YourTable VALUES (1,3,1)
INSERT INTO @YourTable VALUES (1,3,2)
INSERT INTO @YourTable VALUES (1,3,3)
INSERT INTO @YourTable VALUES (2,1,1)
INSERT INTO @YourTable VALUES (2,1,2)
INSERT INTO @YourTable VALUES (2,1,3)
INSERT INTO @YourTable VALUES (2,2,1)
INSERT INTO @YourTable VALUES (2,2,2)
INSERT INTO @YourTable VALUES (2,2,3)
INSERT INTO @YourTable VALUES (2,3,1)
INSERT INTO @YourTable VALUES (2,3,2)
INSERT INTO @YourTable VALUES (2,3,3)
INSERT INTO @YourTable VALUES (3,1,1)
INSERT INTO @YourTable VALUES (3,1,2)
INSERT INTO @YourTable VALUES (3,1,3)
INSERT INTO @YourTable VALUES (3,2,1)
INSERT INTO @YourTable VALUES (3,2,2)
INSERT INTO @YourTable VALUES (3,2,3)
INSERT INTO @YourTable VALUES (3,3,1)
INSERT INTO @YourTable VALUES (3,3,2)
INSERT INTO @YourTable VALUES (3,3,3)
SET NOCOUNT OFF

DECLARE @PageNumber     int
DECLARE @PageSize       int
DECLARE @SortBy         int

SET @PageNumber=3
SET @PageSize=5
SET @SortBy=1


--SELECT * FROM @YourTable

--Method 1
;WITH PaginatedYourTable AS (
SELECT
    RowID,Value1,Value2,Value3
        ,CASE @SortBy
             WHEN  1 THEN ROW_NUMBER() OVER (ORDER BY Value1 ASC)
             WHEN  2 THEN ROW_NUMBER() OVER (ORDER BY Value2 ASC)
             WHEN  3 THEN ROW_NUMBER() OVER (ORDER BY Value3 ASC)
             WHEN -1 THEN ROW_NUMBER() OVER (ORDER BY Value1 DESC)
             WHEN -2 THEN ROW_NUMBER() OVER (ORDER BY Value2 DESC)
             WHEN -3 THEN ROW_NUMBER() OVER (ORDER BY Value3 DESC)
         END AS RowNumber
    FROM @YourTable
    --WHERE
)
SELECT
    RowID,Value1,Value2,Value3,RowNumber
        ,@PageNumber AS PageNumber, @PageSize AS PageSize, @SortBy AS SortBy
    FROM PaginatedYourTable
    WHERE RowNumber>=(@PageNumber-1)*@PageSize AND RowNumber<=(@PageNumber*@PageSize)-1
    ORDER BY RowNumber



--------------------------------------------
--Method 2
;WITH PaginatedYourTable AS (
SELECT
    RowID,Value1,Value2,Value3
        ,ROW_NUMBER() OVER
         (
             ORDER BY
                 CASE @SortBy
                     WHEN  1 THEN Value1
                     WHEN  2 THEN Value2
                     WHEN  3 THEN Value3
                 END ASC
                ,CASE @SortBy
                     WHEN -1 THEN Value1
                     WHEN -2 THEN Value2
                     WHEN -3 THEN Value3
                 END DESC
         ) RowNumber
    FROM @YourTable
    --WHERE  more conditions here
)
SELECT
    RowID,Value1,Value2,Value3,RowNumber
        ,@PageNumber AS PageNumber, @PageSize AS PageSize, @SortBy AS SortBy
    FROM PaginatedYourTable
    WHERE 
        RowNumber>=(@PageNumber-1)*@PageSize AND RowNumber<=(@PageNumber*@PageSize)-1
        --AND more conditions here
    ORDER BY
        CASE @SortBy
            WHEN  1 THEN Value1
            WHEN  2 THEN Value2
            WHEN  3 THEN Value3
        END ASC
       ,CASE @SortBy
            WHEN -1 THEN Value1
            WHEN -2 THEN Value2
            WHEN -3 THEN Value3
        END DESC

산출:

RowID  Value1 Value2 Value3 RowNumber  PageNumber  PageSize    SortBy
------ ------ ------ ------ ---------- ----------- ----------- -----------
10     2      1      1      10         3           5           1
11     2      1      2      11         3           5           1
12     2      1      3      12         3           5           1
13     2      2      1      13         3           5           1
14     2      2      2      14         3           5           1

(5 row(s) affected

RowID  Value1 Value2 Value3 RowNumber  PageNumber  PageSize    SortBy
------ ------ ------ ------ ---------- ----------- ----------- -----------
10     2      1      1      10         3           5           1
11     2      1      2      11         3           5           1
12     2      1      3      12         3           5           1
13     2      2      1      13         3           5           1
14     2      2      2      14         3           5           1

(5 row(s) affected)

1
참고로, SET SHOWPLAN_ALL ON을 사용할 때 방법 1의 TotalSubtreeCost는 0.08424953이고 방법 2는 0.02627153입니다. 방법 2는 3 배 이상 좋았습니다.
KM.

1
@rexem, 방법 1과 2는 모두 CTE를 사용하며 행을 페이지 매김하고 정렬하는 방식이 다릅니다. 나는이 실제 질문은 질문 다르지 확실하지 왜 해요 그 영업 이익 (영업 이익에 의해이 질문에 대한 대답)에 대한 링크,하지만 내 대답은 OP가 참조하는 링크를 기반으로 작업 코드 생성
KM.

1
감사합니다. 이전 게시물과이 답변을 비교하려고합니다. [포맷하는 방법을 모르겠습니다] 다음은 Tomalak에서 제공 한 답변입니다. stackoverflow.com/questions/230058?sort=votes#sort-top 이것이 잘못 되었습니까? 그가 답변의 절반 만 게시했다면 어떻게하면 더 나은 쿼리 수행 방식을 사용할 수 있을까요? 계속 진행할 수 있도록 좀 더 빛을주세요. 감사합니다

제공 한 링크 ( stackoverflow.com/questions/230058?sort=votes#sort-top ) 에서 선택한 답변 인 @Joseph 가 질문을 한 사람이 답변에서 작업 할 때 제공 하는 작업 코드와 다릅니다. stackoverflow.com/ 질문 / 230058 /… 해당 답변을 읽으면 해당 코드에 대한 링크 : pastebin.com/f26a4b403 및 해당 버전의 Tomalak에 대한 링크 : pastebin.com/f4db89a8e 내 답변에 각 버전의 작업 버전을 제공합니다. 테이블 변수
KM.

2
WITH MyCte AS 
(
    select 
       employee_id,
       RowNum = row_number() OVER (order by employee_id)
    from V_EMPLOYEE 
)
SELECT  employee_id
FROM    MyCte
WHERE   RowNum > 0
ORDER BY employee_id

-1
 select salary from (
 select  Salary, ROW_NUMBER() over (order by Salary desc) rn from Employee 
 ) t where t.rn = 2

3
Stack Overflow에 오신 것을 환영합니다! 이 코드 조각이 해결책이 될 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 도움이됩니다. 미래에 독자를 위해 질문에 답하고 있으며 해당 사용자는 코드 제안 이유를 모를 수 있습니다.
Johan

향후 독자 를 위해 코드 스 니펫 에 컨텍스트를 추가하십시오 .
DebanjanB
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.