Znalazłem odpowiedź na jedno pytanie z Row_Number()
funkcją w klauzuli where. Kiedy wypróbowałem jedno zapytanie, otrzymałem następujący błąd:
„Msg 4108, poziom 15, stan 1, wiersz 1 Funkcje okienkowe mogą pojawiać się tylko w klauzulach SELECT lub ORDER BY”.
Oto zapytanie, które wypróbowałem. Jeśli ktoś wie, jak to rozwiązać, daj mi znać.
SELECT employee_id
FROM V_EMPLOYEE
WHERE row_number() OVER ( ORDER BY employee_id ) > 0
ORDER BY Employee_ID
sql
sql-server
tsql
analytic-functions
johnnyRose
źródło
źródło
ROW_NUMBER() OVER (ORDER BY employee_id) > 0
zawsze oceniTRUE
Odpowiedzi:
Aby obejść ten problem, zawiń instrukcję select w CTE, a następnie możesz wykonać zapytanie dotyczące CTE i użyć wyników funkcji okienkowej w klauzuli 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
źródło
ROW_NUMBER()
wWHERE
klauzuli bez CTE :(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
Zauważ, że ten filtr jest nadmiarowy:
ROW_NUMBER()
zaczyna się od1
i jest zawsze większy niż0
.źródło
AS q
zamiast tego powinienem był napisać , ale to też zadziała).rn
jest obecnie powszechnie akceptowanym akronimem dla numeru wiersza. Spróbuj wpisać „numer_wiersza na jako ...” w ciągu wyszukiwania Google i zobacz, co sugeruje.Select * from ( Select ROW_NUMBER() OVER ( order by Id) as 'Row_Number', * from tbl_Contact_Us ) as tbl Where tbl.Row_Number = 5
źródło
Myślę, że chcesz coś takiego:
SELECT employee_id FROM (SELECT employee_id, row_number() OVER (order by employee_id) AS 'rownumber' FROM V_EMPLOYEE) TableExpressionsMustHaveAnAliasForDumbReasons WHERE rownumber > 0
źródło
From V_EMPLOYEE) A
, dodając A jako alias.W odpowiedzi na komentarze do odpowiedzi rexem, w odniesieniu do tego, czy widok inline lub CTE byłby szybszy, przekształcam zapytania tak, aby korzystały z tabeli, którą ja i wszyscy mieliśmy dostępni: 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
Utworzone plany zapytań były dokładnie takie same. Spodziewałbym się, że we wszystkich przypadkach optymalizator zapytań wymyśli ten sam plan, przynajmniej w prostej zamianie CTE na widok inline lub odwrotnie.
Oczywiście wypróbuj własne zapytania we własnym systemie, aby sprawdzić, czy istnieje różnica.
Również
row_number()
w klauzuli where jest częstym błędem w odpowiedziach udzielonych na Stack Overflow. Logicznierow_number()
nie jest dostępna, dopóki nie zostanie przetworzona klauzula select. Ludzie o tym zapominają, a kiedy odpowiadają bez sprawdzania odpowiedzi, czasami odpowiedź jest błędna. (Zarzut, który sam jestem winny).źródło
Wydaje mi się, że wszystkie odpowiedzi pokazujące użycie CTE lub Sub Query są wystarczającymi poprawkami, ale nie widzę, aby ktokolwiek docierał do sedna, dlaczego OP ma problem. Powodem, dla którego to, co sugeruje OP, nie działa, jest logiczna kolejność przetwarzania zapytań tutaj:
Uważam, że to bardzo przyczynia się do odpowiedzi, ponieważ wyjaśnia, dlaczego pojawiają się problemy takie jak ten.
WHERE
jest zawsze przetwarzany przedSELECT
wykonaniem CTE lub zapytania podrzędnego niezbędnego dla wielu funkcji. Zobaczysz to często w SQL Server.źródło
Korzystanie z 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
Korzystanie z widoku w wierszu / alternatywy bez odpowiednika 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
źródło
SQL Server
,CTE
„s inline i poglądy są tak samo i mają taką samą wydajność. Gdy funkcje niedeterministyczne są używane w aCTE
, jego wartość jest ponownie oceniana przy każdym wywołaniu. Trzeba używać brudnych sztuczek, aby wymusić materializacjęCTE
. Zobacz te artykuły w moim blogu: explainextended.com/2009/07/28/... explainextended.com/2009/05/28/generating-xml-in-subqueriesna podstawie odpowiedzi OP na pytanie:
„metoda 1” jest podobna do zapytania OP z połączonego pytania, a „metoda 2” jest podobna do zapytania z wybranej odpowiedzi. Trzeba było spojrzeć na kod powiązany w tej odpowiedzi, aby zobaczyć, co się naprawdę dzieje, ponieważ kod w wybranej odpowiedzi został zmodyfikowany, aby działał. Spróbuj tego:
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
WYNIK:
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)
źródło
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
źródło
select salary from ( select Salary, ROW_NUMBER() over (order by Salary desc) rn from Employee ) t where t.rn = 2
źródło