web-dev-qa-db-fra.com

Fonction SQL Row_Number () dans la clause Where

J'ai trouvé une réponse à la question avec la fonction Row_Number() dans la clause where. Lorsque j'ai essayé une requête, j'obtenais l'erreur suivante:

"Msg 4108, Les fonctions fenêtrées de niveau 1, Etat 1, Ligne 1 ne peuvent apparaître que dans les clauses SELECT ou ORDER BY."

Voici la requête que j'ai essayée. Si quelqu'un sait comment résoudre ce problème, s'il vous plaît faites le moi savoir.

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

Pour contourner ce problème, encapsulez votre instruction select dans un CTE, puis vous pourrez interroger ce dernier et utiliser les résultats de la fonction fenêtrée dans la clause 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
81
Scott Ivey
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

Notez que ce filtre est redondant: ROW_NUMBER() commence à partir de 1 Et est toujours supérieur à 0.

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

Je pense que tu veux quelque chose comme ça:

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

En réponse aux commentaires sur la réponse de rexem, à savoir si une vue en ligne ou un CTE serait plus rapide, je reformule les requêtes pour utiliser un tableau que tout le monde avait: 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

Les plans de requête produits étaient exactement les mêmes. Je pense que dans tous les cas, l'optimiseur de requêtes proposerait le même plan, du moins en remplaçant simplement CTE par la vue en ligne ou vice versa.

Bien sûr, essayez vos propres requêtes sur votre propre système pour voir s'il y a une différence.

De plus, row_number() dans la clause where est une erreur courante dans les réponses données lors du dépassement de pile. Logicaly row_number() n'est pas disponible jusqu'à ce que la clause select soit traitée. Les gens oublient cela et quand ils répondent sans tester la réponse, la réponse est parfois fausse. (Une accusation que j'ai moi-même été coupable.)

7
Shannon Severance

Utilisation de 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

Utilisation de la vue en ligne/équivalent 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
4
OMG Ponies

basé sur la réponse de OP à la question:

S'il vous plaît voir ce lien. Sa solution différente, qui semble fonctionner pour la personne qui a posé la question. J'essaie de trouver une solution comme celle-ci.

Requête paginée utilisant le tri sur différentes colonnes à l'aide de ROW_NUMBER () OVER () dans SQL Server 2005

~ Joseph

"méthode 1" est semblable à la requête du PO à partir de la question liée et "méthode 2" à la requête de la réponse sélectionnée. Il fallait regarder le code lié dans ce réponse pour voir ce qui se passait réellement, car le code de la réponse sélectionnée a été modifié pour le faire fonctionner. Essaye ça:

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

SORTIE:

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)
2
KM.
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
2
sumit

J'ai le sentiment que toutes les réponses montrant l'utilisation d'un CTE ou d'une sous-requête sont des solutions suffisantes, mais je ne vois personne expliquer au cœur de la raison pour laquelle OP a un problème. La raison pour laquelle l'OP suggéré ne fonctionne pas est due à l'ordre de traitement des requêtes logiques ici:

  1. DE
  2. SUR
  3. JOINDRE
  4. PAR GROUPE
  5. AVEC CUBE/ROLLUP
  6. AYANT
  7. SÉLECTIONNER
  8. DISTINCT
  9. COMMANDÉ PAR
  10. HAUT
  11. OFFSET/FETCH

Je pense que cela contribue grandement à la réponse, car cela explique pourquoi des problèmes comme celui-ci se produisent. WHERE est toujours traité avant SELECT rendant un CTE ou une sous-requête nécessaire à de nombreuses fonctions. Vous verrez cela souvent dans SQL Server.

0
Jamie Marshall