Mim

Select * from Seb where Sujets in (SQL Server 2008, ADO.NET, Visual Studio 2008)

Pagination avec SQL Server 2005 : CTE, Row_Number

Aujourd'hui petite astuce pour faire de la pagination de données avec SQL Server 2005 :

Vous avez suremment déjà "exploré" les solutions mises en oeuvres par les scripts SQL des MemberShip Providers pour faire de la pagination de données.
Et comme moi, peut être, vous avez trouvé ça quelque peu ... lourd.

Bon, en même temps, ces scripts se veulent compatibles avec SQL Server 2000 par exemple. De ce fait, les cht'i gars de chez MS n'avaient guère le choix ...

Mais nous, si !

Alors comment faire pour récupérer un jeu de données paginées ?

Tout d'abord, nous allons utiliser Row_Number(), qui a la bonne idée de retourner un numéro de ligne

Par exemple :

Select Row_Number() over (order by BirthDate asc) as RowNumber, E.EmployeeID, E.ManagerID,
E.BirthDate From HumanResources.Employee E

retourne :

1        268       273         1941-11-17
2        246      51          1942-04-03
3        238       274        1942-06-13
4        9         3            1942-10-29
5        237       108        1943-06-01
6        260      49          1944-05-25
7        243      18          1945-03-02
8       7         21           1946-02-16
9       10        185          1946-04-27
10      19        185          1946-04-30
11      14        21            1946-05-03
12      17        185          1946-05-06

Malheuresement, Row_Number() est analysé par le moteur APRES la clause WHERE.
Du coup interdiction de faire quelque chose du genre :

 
where Row_Number() over (order by BirthDate asc) > 100 
and Row_Number() over (order by BirthDate asc) < 120

D'où l'idée d'utiliser une Common Type Expression, qui aura la bonne idée de nous fournir notre précieuse information !

Ce qui donne dans notre exemple :

With mCte (RowNumber, EmployeeID, ManagerID, BirthDate)
As
(
 Select Row_Number() over (order by BirthDate asc) as RowNumber, E.EmployeeID, 
E.ManagerID, E.BirthDate From HumanResources.Employee E ) Select * From mCte C Where RowNumber Between 100 and 120

Avec ASP.Net et une data source, il est de bon ton de donner un numéro de page et un nombre d'enregistrements à récupérer.

Si on arrange tout ça pour s'adapter à ce contexte, on obtient une procédure stockée du style :

CREATE procedure [GetEmployeesPaged]
(
    @nStartRowNum int = 100,
    @nStartRowCount int = 10
    
)

as

With mCte (RowNumber, EmployeeID, ManagerID, BirthDate)
As
(
 Select Row_Number() over (order by BirthDate asc) as RowNumber, 
 E.EmployeeID, E.ManagerID, E.BirthDate
 From    HumanResources.Employee E
)
Select    *
From mCte C
Where    RowNumber Between @nStartRowNum and (@nStartRowNum + @nStartRowCount -1)

Pour aller plus loin :

Si on pousse un peu, je vous propose une Double CTE pour récupérer non seulement les employés mais aussi les managers de ceux ci, ce qui va nous obliger à faire une boucle récursive, ce qui est naturel avec une CTE.

bref, plus que des mots ... du SQL !

With    
    EmpCTE (EmpID, MgrID, Level)
    As    (
         Select E.EmployeeID, E.ManagerID, 1 
         From    HumanResources.Employee E
         Where ManagerID is null
         UNION ALL
         Select E.EmployeeID, E.ManagerID, Level + 1 
         From    HumanResources.Employee E
         Inner Join EmpCTE on EmpCTE.EmpID = E.ManagerID
         ),
    myCTE 
    As (    
        Select    Row_Number() over (order by Level asc) as RowNum, *
        From    EmpCTE
        )

Select    C.RowNum, C.EmpID, CE.FirstName+ ' ' + CE.LastName as EmpName,
        C.MgrID, ME.FirstName+ ' ' + ME.LastName as MgrName, C.Level
From myCTE C
Inner Join Person.Contact CE on C.EmpID = CE.ContactID
Left Outer Join Person.Contact ME on C.MgrID = ME.ContactID

Where    RowNum Between @nStartRowNum and (@nStartRowNum + @nStartRowCount -1)

C'est beau non  ;) ?

Posted: oct. 25 2007, 06:32 par Mimetis | avec 1 comment(s)
Classé sous :

Commentaires

Julien a dit :

Pas mal du tout ce code et bien pratique !

# octobre 26, 2007 9:20
Laissez un commentaire

(requis) 

(requis) 

(optionel(le))

(requis) 


Enter the numbers above: