views:

1111

answers:

7

Hi All, I found one question answered with Row_Number() function in where clause. When I tried one query, I was getting the following error.

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

Here is the query I tried. If somebody knows how to solve this, please let me know. Thanks in Advance.

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

~Joseph

+3  A: 
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

Note that this filter is redundant: ROW_NUMBER() starts from 1 and is always greater than 0.

Quassnoi
+7  A: 

To get around this issue, wrap your select statement in a CTE, and then you can query against the CTE and use the windowed function's results in the where clause.

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
Scott Ivey
I'm trying to avoid CTE. Thats the worse case I'm looking for.thanks
Joseph
+1  A: 

I think you want something like this:

SELECT employee_id FROM 
(SELECT employee_id, row_number() OVER (order by employee_id) AS 'rownumber' FROM V_EMPLOYEE)
WHERE rownumber > 0
Matthew Jones
+3  A: 

Using 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

Using Inline view/Non-CTE Equivalent Alternative:

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
OMG Ponies
Which one better in performance? Using CTE or subquery?thanks
Joseph
See Shannon's answer - in his test they are equal.
OMG Ponies
No, it's not faster. In `SQL Server`, `CTE`'s and inline views are the same thing and have same performance. When non-deterministic functions are used in a `CTE`, its reevaluated on each call. One has to use dirty tricks to force materializationof a `CTE`. See these articles in my blog: http://explainextended.com/2009/07/28/sql-server-random-records-avoiding-cte-reevaluation/ http://explainextended.com/2009/05/28/generating-xml-in-subqueries/
Quassnoi
A: 

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.

http://stackoverflow.com/questions/230058/paginated-query-using-sorting-on-different-columns-using-rownumber-over-in

~Joseph

Joseph
Joseph, if you look at that page, Leandro Lopez has an answer where he links to his version and Tomalak's version. Tomalak's version is different than what was giving in Tomalak's answer, and has the row_number() function moved into a CTE.
Shannon Severance
+2  A: 

In response to comments on rexem's answer, with respect to whether a an inline view or CTE would be faster I recast the queries to use a table I, and everyone, had available: 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

The query plans produced were exactly the same. I would expect in all cases, the query optimizer would come up with the same plan, at least in simple replacement of CTE with inline view or vice versa.

Of course, try your own queries on your own system to see if there is a difference.

Also, row_number() in the where clause is a common error in answers given on Stack Overflow. Logicaly row_number() is not available until the select clause is processed. People forget that and when they answer without testing the answer, the answer is sometimes wrong. (A charge I have myself been guilty of.)

Shannon Severance
Thx Shannon. What version of SQL Server were you using?
OMG Ponies
So that means, the answer provided in that link is wrong? But, the person who posted the question agreed that its working.. Surprising.. :-)
Joseph
@Joseph, but if you look at another answer posted by the OP in the linked question, you will see that he link's to a version of the code that is not the same as in the accepted answer. I don't know why he accepted the answer, even though it would not run as entered. Maybe it was edited at some point after being accepted, maybe it was enough to get him going, even without being totally correct.
Shannon Severance
Shannon Severance
+1 for the reminder about the timing of the WHERE clause.
onedaywhen
+1  A: 

based on OP's answer to question:

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.

http://stackoverflow.com/questions/230058/paginated-query-using-sorting-on-different-columns-using-rownumber-over-in

~Joseph

"method 1" is like the OP's query from the linked question, and "method 2" is like the query from the selected answer. You had to look at the code linked in this answer to see what was really going on, since the code in the selected answer was modified to make it work. Try this:

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

OUTPUT:

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)
KM
fyi, when using _SET SHOWPLAN_ALL ON_ method 1 had a TotalSubtreeCost of 0.08424953, while method 2 was at 0.02627153. method 2 was over three times better.
KM
Sorry - method 2 is the inline view or CTE, correct?
OMG Ponies
@rexem, both method 1 and 2 use CTEs, the way they paginate and order rows is different. I'm not sure why this actual question is so different from the question that the OP links to (in the answer to this question by the OP), but my answer creates working code based on the link that the OP refers to
KM
@KM: Sorry, I didn't read fully.
OMG Ponies
Thanks, I'm trying to compare the old post and this answers. [I don't know how to format this] Here is the answer provided by Tomalak.http://stackoverflow.com/questions/230058?sort=votes#sort-topIs this wrong? If he posted only half of the answer, how will I go ahead with his better performance way of doing my query? Please give me some more light to proceed..thanks
Joseph
@Joseph, the selected answer in the link you provide (http://stackoverflow.com/questions/230058?sort=votes#sort-top) differs from the working code that the person asking the question provides as working in their answer: http://stackoverflow.com/questions/230058/paginated-query-using-sorting-on-different-columns-using-rownumber-over-in/240108#240108 if you read that answer you will see a link to their code: http://pastebin.com/f26a4b403 and a link to their version of Tomalak's: http://pastebin.com/f4db89a8e in my answer I provide a working version of each version using table variables
KM