Функция SQL Row_Number() в разделе Where Where

Я нашел один вопрос, отвечающий с помощью функции 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

Ответ 1

Чтобы обойти эту проблему, оберните оператор 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

Ответ 2

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.

Ответ 3

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

Ответ 4

Я думаю, вам нужно что-то вроде этого:

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

Ответ 5

В ответ на комментарии к ответу 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 является общей ошибкой в ​​ответах, приведенных в разделе Переполнение стека. Логически row_number() недоступен до тех пор, пока не будет обработано предложение select. Люди забывают об этом, и когда они отвечают без проверки ответа, ответ иногда ошибочен. (Обвинение, в котором я сам виноват.)

Ответ 6

Использование 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

Использование Inline view/Non-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

Ответ 7

на основе ответа OP на вопрос:

Пожалуйста, просмотрите эту ссылку. Имея другое решение, которое выглядит работая для человека, который спросил вопрос. Я пытаюсь выяснить решение, подобное этому.

Разбитый запрос с использованием сортировки по разным столбцам с использованием ROW_NUMBER() OVER() в SQL Server 2005

~ Джозеф

"метод 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)

Ответ 8

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

Ответ 9

Я чувствую, что все ответы, показывающие использование CTE или подзапроса, являются достаточными исправлениями для этого, но я не вижу, чтобы кто-то понимал, почему у OP есть проблема. Причина, по которой предложенный OP не работает, заключается в том, что логический порядок обработки запросов здесь:

  1. ОТ
  2. ON
  3. РЕГИСТРИРУЙТЕСЬ
  4. ГДЕ
  5. GROUP BY
  6. С КУБОМ /ROLLUP
  7. HAVING
  8. ВЫБРАТЬ
  9. DISTINCT
  10. ЗАКАЗАТЬ
  11. TOP
  12. OFFSET/FETCH

Я считаю, что это очень помогает в ответе, потому что объясняет, почему возникают подобные проблемы. WHERE всегда обрабатывается перед тем, как SELECT делает CTE или подзапрос, необходимый для многих функций. Вы многое увидите в SQL Server.

Ответ 10

если необходимо добавить условие динамически, вы можете использовать в запросе:

SELECT f0.*
FROM FOO f0
WHERE EXISTS
  (SELECT f2.foo_id
  FROM
    (SELECT foo_id ,
      ROW_NUMBER() OVER( PARTITION BY F1.BAR_ID ORDER BY F1.AMOUNT) rk
    FROM foo f1
    )f2
  WHERE f0.foo_id=f2.foo_id
  AND rk         =2 -- your condition on row_number goes here
  );

Ответ 11

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