2009-09-23 3 views
63

Я нашел один вопрос с помощью функции Row_Number() в предложении where. Когда я попробовал один запрос, я получил следующую ошибку:Функция SQL Row_Number() в месте где

"Msg 4108, Level 15, State 1, Line 1 Windowed functions can only appear in the SELECT or ORDER BY clauses."

Вот запрос, который я пробовал. Если кто-то знает, как это решить, сообщите мне.

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

'ROW_NUMBER() OVER (ORDER BY employee_id)> 0' всегда будет оценивать значение 'TRUE' – Quassnoi

+1

Yea , это верно. Меня не беспокоит состояние, которое я могу изменить в любое время. Я хочу, чтобы запрос работал первым, а затем подумал о том, чтобы сохранить номер журнала от 500 до 800 ... спасибо – 2009-09-23 17:31:00

+1

@Joseph: Почему вы пытаетесь избежать использования CTE? –

ответ

49
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.

+0

Отлично. Это помогло мне тонну. Спасибо. –

+0

@Quassnoi Спасибо! Любопытство: почему существует 'q'? Что это значит? –

+1

@ DavideChicco.it: в SQL Server производные таблицы требуют псевдонима (я должен был написать 'AS q', но это тоже сработало). – Quassnoi

69

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

Я стараюсь избегать CTE. Это худший случай, который я ищу. thanks – 2009-09-23 17:32:05

+2

Он может работать быстрее, если вы используете подзапрос вместо CTE. Я видел более высокую производительность в 1,5 раза в некоторых случаях –

+0

Могу ли я использовать С в подзапросе – Xulfee

14

Я думаю, что вы хотите что-то вроде этого:

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

Создайте псевдоним для таблицы, если указанный выше запрос не работает для вас. Измените вторую последнюю строку как «Из V_EMPLOYEE» A', которая добавляет A как псевдоним. –

3

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

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

Какая из лучших в производительности? Использование CTE или подзапроса? спасибо – 2009-09-23 17:32:50

+0

См. Ответ Шеннона - в его тесте они равны. –

+5

Нет, это не быстрее. В 'SQL Server',' CTE' и встроенные представления - одно и то же и имеют одинаковую производительность. Когда не-детерминированные функции используются в «CTE», он переоценивается при каждом вызове. Нужно использовать грязные трюки, чтобы заставить материализацию «CTE». Смотрите эти статьи в своем блоге: http: // explainextended.com/2009/07/28/sql-server-random-records-avoiding-cte-reevaluation/http://explainextended.com/2009/05/28/generating-xml-in-subqueries/ – Quassnoi

5

В ответ на комментарии к rexem's ответ, в отношении того, будет ли быстрый просмотр или 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. Люди забывают об этом, и когда они отвечают без проверки ответа, ответ иногда ошибочен. (Сбор я сам был виновен.)

+0

Thx Shannon. Какую версию SQL Server вы использовали? –

+0

Значит, ответ, указанный в этой ссылке, неверен? Но, человек, который разместил вопрос, согласился, что его работа .. Удивительно .. :-) – 2009-09-23 20:45:02

+1

@Joseph, но если вы посмотрите на другой ответ, отправленный OP в связанном вопросе, вы увидите, что он ссылается на версию код, который не совпадает с принятым ответом. Я не знаю, почему он принял ответ, даже если он не запустится, как введенный. Может быть, он был отредактирован в какой-то момент после его принятия, возможно, этого было достаточно, чтобы заставить его идти, даже не будучи абсолютно правильным. –

1

на основе ответа ФП к вопросу:

Please see this link. Its having a different solution, which looks working for the person who asked the question. I'm trying to figure out a solution like this.

Paginated query using sorting on different columns using ROW_NUMBER() OVER() in SQL Server 2005

~Joseph

«Метод 1», как запрос на ФП в от связанного вопроса, и «метод 2», как запрос из выбранного ответа. Вам нужно было посмотреть код, связанный в этом answer, чтобы узнать, что действительно происходит, поскольку код в выбранном ответе был изменен, чтобы заставить его работать.Попробуйте это:

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) 
+0

fyi, при использовании метода _SET SHOWPLAN_ALL ON_ 1 имел значение TotalSubtreeCost 0.08424953, а метод 2 - 0,02627153. метод 2 был более чем в три раза лучше. –

+0

Извините - метод 2 - это встроенный просмотр или CTE, правильно? –

+0

@rexem, оба метода 1 и 2 используют CTE, то, как они разбиваются на страницы и упорядочивать строки, различны. Я не уверен, почему этот фактический вопрос настолько отличается от вопроса, что OP связывается с (в ответе на этот вопрос OP), но мой ответ создает рабочий код на основе ссылки, которую OP ссылается на –

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

хороший пример! thx очень – richin

+1

Спасибо за отличный пример! Это действительно помогло, так как мне нужна эта функциональность для работы с старой базой данных SQL Server 2000, где CTE не существует. – StarPilot

-1
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 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 
); 

 Смежные вопросы

  • Нет связанных вопросов^_^