Where句のSQL Row_Number()関数


90

Row_Number()where句の関数で答えられる質問が1つ見つかりました。1つのクエリを実行すると、次のエラーが発生しました。

「メッセージ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 09/09/23

3
うん、そうだね。いつでも変更できるコンディションは気になりません。最初にクエリを機能させてから、行番号を500から800の間に保つことを考えています...感謝

2
@ジョセフ:なぜCTEの使用を避けようとしているのですか?
OMGポニー

1
@rexem-SQL Serverの専門家ではありません。パフォーマンスに関する多くの問題に直面している大きなプロジェクトのチームを支援しようとしています。彼らはUDFとCTEを使用しています。テーブルの1つには5000レコードしかありません。5人のユーザーが検索にアクセスすると、取得に1分以上かかります。しばらくすると、失敗してタイムアウトします。したがって、私はCTEとUDFを避け、パフォーマンスの問題を解決できる単純なSQLクエリを考え出そうとしています。

1
こんにちは、以下に掲載したリンクで、row_number()を別の方法で使用して回答を確認してください。誰かが私の最初のクエリをリンクのクエリと比較できますか?助けに感謝...

回答:


91

この問題を回避するには、selectステートメントをCTEでラップしてから、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倍のパフォーマンスの向上を見てきました
ブライアンウェブスター

3
CTE SELECTにもTOPが含まれている必要があります。そうでない場合、ORDER BY(TOPを使用しない限りサポートされない)のためにSQL 2008 Serverがクエリを実行しません
Muflix

2
私はSQL2005(ugh)を使用しています-FROMの後に「ORDER BY」をドロップすることで、「TOP」の使用を回避できます。とにかくOVERの後の(Order By)と冗長です。
ジョーB

CTEなしROW_NUMBER()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、2016

2
読みやすさは、エイリアスに名前を付けるときに私が持っている焦点です。rnをRowNumberとして、qをDerivedTableとして、where句を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に出会ったことがないので、「ユニバーサル」での走行距離は異なる場合があります。
エドワードコモー

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
上記のクエリが機能しない場合は、テーブルのエイリアスを作成します。最後の2行目を変更してFrom V_EMPLOYEE) A、エイリアスとしてAを追加します。
Hammad Khan 2014

7

rexemの回答に関するコメントに応じて、インラインビューとCTEのどちらが速くなるかについて、クエリを再キャストして、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句は、スタックオーバーフローで返される一般的なエラーです。論理的にrow_number()は、select句が処理されるまで使用できません。人々はそれを忘れ、彼らが答えをテストせずに答えると、答えは時々間違っています。(私が罪を犯した罪)


1
Thxシャノン。使用しているSQL Serverのバージョンは何ですか?
OMGポニー

1
つまり、そのリンクで提供される答えは間違っていますか?しかし、質問を投稿した人は、それが機能することに同意しました..驚くべきこと.. :-)

2
@Joseph、しかしリンクされた質問でOPによって投稿された別の回答を見ると、彼がリンクが受け入れられた回答とは異なるバージョンのコードにリンクしていることがわかります。入力したとおりに実行されないのに、なぜ彼が答えを受け入れたのかわかりません。多分それは受け入れられた後のある時点で編集されたかもしれません、多分彼は完全に正しくなくても彼を動かすのに十分でした。
シャノン退職

1
@Rexem:SQL Server 2005とSQL Server 2008の両方。以前のバージョンはCTEまたはROW_NUMBER()をサポートしていません
Shannon Severance

6

CTEまたはサブクエリの使用を示すすべての回答はこれに対する十分な修正であるように感じますが、OPに問題がある理由の核心を誰かが理解しているようには見えません。OPの提案が機能しない理由は、ここでの論理的なクエリ処理順序が原因です。

  1. から
  2. オン
  3. 参加する
  4. どこ
  5. GROUP BY
  6. キューブ/ロールアップあり
  7. 持っている
  8. 選択する
  9. 明確な
  10. 注文する
  11. オフセット/フェッチ

このような問題が発生する理由を説明しているので、これは答えに大きく貢献していると思います。多くの機能でCTEまたはサブクエリが必要になるWHERE前に常に処理さSELECTれます。これは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
シャノンの答えを見てください-彼のテストでは、それらは等しいです。
OMGポニー

6
いいえ、速くはありません。ではSQL ServerCTEとインラインビューは同じものであり、同じパフォーマンスを持っています。非決定的関数がで使用されている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
fyi、SET SHOWPLAN_ALL ONを使用する場合、メソッド1のTotalSubtreeCostは0.08424953でしたが、メソッド2は0.02627153でした。方法2は3倍以上優れていました。
和基。

1
@rexem、方法1と2の両方でCTEを使用します。ページングと行の順序付けの方法が異なります。この実際の質問はOPリンク(OPことで、この質問への答えで)にいることを質問からそう異なりますが、私の答えはOPが参照するリンクに基づいて動作するコードを作成、なぜ私はわからない
KMを。

1
おかげで、私は古い投稿とこの回答を比較しようとしています。[これをフォーマットする方法がわかりません] Tomalakが提供する答えは次のとおりです。stackoverflow.com/questions/230058?sort=votes#sort-top これは間違っていますか?彼が答えの半分しか投稿しなかった場合、クエリを実行する彼のより良いパフォーマンスの方法をどのように進めますか?先に進むには、もう少し光をください。ありがとう

@Joseph、提供するリンクで選択した回答(stackoverflow.com/questions/230058?sort=votes#sort-top)は、質問をする人が回答で機能するものとして提供する機能コードとは異なります: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.