web-dev-qa-db-fra.com

Équivalent de LIMIT et OFFSET pour SQL Server?

Dans PostgreSQL, il y a les mots-clés Limit et Offset qui permettront une pagination très facile des ensembles de résultats.

Quelle est la syntaxe équivalente pour Sql Server?

156
Earlz

L'équivalent de LIMIT est SET ROWCOUNT, mais si vous voulez une pagination générique, il est préférable d'écrire une requête comme celle-ci:

;WITH Results_CTE AS
(
    SELECT
        Col1, Col2, ...,
        ROW_NUMBER() OVER (ORDER BY SortCol1, SortCol2, ...) AS RowNum
    FROM Table
    WHERE <whatever>
)
SELECT *
FROM Results_CTE
WHERE RowNum >= @Offset
AND RowNum < @Offset + @Limit

L’avantage ici est le paramétrage du décalage et de la limite si vous décidez de modifier vos options de pagination (ou autorisez l’utilisateur à le faire).

Remarque: le paramètre @Offset devrait utiliser une indexation à base unique pour cela, plutôt que l'indexation normale à base zéro.

133
Aaronaught

Cette fonctionnalité est désormais simplifiée dans SQL Server 2012. Cela fonctionne à partir de SQL Server 2012.

Limiter avec décalage pour sélectionner 11 à 20 lignes dans SQL Server:

SELECT email FROM emailTable 
WHERE user_id=3
ORDER BY Id
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
  • OFFSET: nombre de lignes ignorées
  • NEXT: nombre requis de lignes suivantes

Référence: https://docs.Microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

209
Somnath Muluk
select top {LIMIT HERE} * from (
      select *, ROW_NUMBER() over (order by {ORDER FIELD}) as r_n_n 
      from {YOUR TABLES} where {OTHER OPTIONAL FILTERS}
) xx where r_n_n >={OFFSET HERE}

Remarque: Cette solution ne fonctionnera que sous SQL Server 2005 ou supérieur, car c'était à l'époque où ROW_NUMBER() était implémenté.

23
jorgeu

Vous pouvez utiliser ROW_NUMBER dans une expression de table commune pour y parvenir.

;WITH My_CTE AS
(
     SELECT
          col1,
          col2,
          ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
)
SELECT
     col1,
     col2
FROM
     My_CTE
WHERE
     row_number BETWEEN @start_row AND @end_row
11
Tom H

Pour moi, l'utilisation de OFFSET et FETCH ensemble était lente, j'ai donc utilisé une combinaison de TOP et OFFSET comme celle-ci (qui était plus rapide):

SELECT TOP 20 * FROM (SELECT columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

Note: Si vous utilisez TOP et OFFSET ensemble dans la même requête comme:

SELECT TOP 20 columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS

Ensuite, vous obtenez une erreur. Par conséquent, pour utiliser TOP et OFFSET ensemble, vous devez la séparer par une sous-requête.

Et si vous devez utiliser SELECT DISTINCT, la requête est la suivante:

SELECT TOP 20 FROM (SELECT DISTINCT columname1, columname2
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

Note: L'utilisation de SELECT ROW_NUMBER avec DISTINCT n'a pas fonctionné pour moi.

3
sebasdev

Le plus proche que je puisse faire est

select * FROM( SELECT *, ROW_NUMBER() over (ORDER BY ID ) as ct from [db].[dbo].[table] ) sub where ct > fromNumber  and ct <= toNumber

Qui je suppose semblable à select * from [db].[dbo].[table] LIMIT 0, 10

2
user2991730

Ajoutant une légère variation à la solution d'Aaronaught, je paramètre généralement le numéro de page (@PageNum) et la taille de la page (@PageSize). Ainsi, chaque événement de clic de page envoie simplement le numéro de page demandé avec une taille de page configurable:

begin
    with My_CTE  as
    (
         SELECT col1,
              ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
    )
    select * from My_CTE
            WHERE RowNum BETWEEN (@PageNum - 1) * (@PageSize + 1) 
                              AND @PageNum * @PageSize

end
2
Tom

Il y a ici quelqu'un parle de cette fonctionnalité dans sql 2011, c'est triste qu'ils aient choisi un mot-clé un peu différent "OFFSET/FETCH" mais ce n'est pas standard alors ok.

2
-- @RowsPerPage  can be a fixed number and @PageNumber number can be passed 
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 2

SELECT *

FROM MemberEmployeeData

ORDER BY EmployeeNumber

OFFSET @PageNumber*@RowsPerPage ROWS

FETCH NEXT 10 ROWS ONLY
2
shakeel

Un autre échantillon:

declare @limit int 
declare @offset int 
set @offset = 2;
set @limit = 20;
declare @count int
declare @idxini int 
declare @idxfim int 
select @idxfim = @offset * @limit
select @idxini = @idxfim - (@limit-1);
WITH paging AS
    (
        SELECT 
             ROW_NUMBER() OVER (order by object_id) AS rowid, *
        FROM 
            sys.objects 
    )
select *
    from 
        (select COUNT(1) as rowqtd from paging) qtd, 
            paging 
    where 
        rowid between @idxini and @idxfim
    order by 
        rowid;
2
sillyim

Puisque personne n'a encore fourni ce code:

SELECT TOP @limit f1, f2, f3...
FROM t1
WHERE c1 = v1, c2 > v2...
AND
    t1.id NOT IN
        (SELECT TOP @offset id
         FROM t1
         WHERE c1 = v1, c2 > v2...
         ORDER BY o1, o2...)
ORDER BY o1, o2...

Les points importants:

  • ORDER BY doit être identique
  • @limit peut être remplacé par le nombre de résultats à récupérer,
  • @offset est le nombre de résultats à ignorer
  • Veuillez comparer les performances avec les solutions précédentes car elles pourraient être plus efficaces.
  • cette solution duplique les clauses where et order by et fournit des résultats incorrects si elles ne sont pas synchronisées
  • d'autre part order by est-il explicitement si c'est ce qui est nécessaire
1
przemo_li
@nombre_row :nombre ligne par page  
@page:numero de la page

//--------------code sql---------------

declare  @page int,@nombre_row int;
    set @page='2';
    set @nombre_row=5;
    SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY etudiant_ID ) AS RowNum, *
      FROM      etudiant

    ) AS RowConstrainedResult
WHERE   RowNum >= ((@page-1)*@nombre_row)+1
    AND RowNum < ((@page)*@nombre_row)+1
ORDER BY RowNum
1
select top (@TakeCount) * --FETCH NEXT
from(
    Select  ROW_NUMBER() OVER (order by StartDate) AS rowid,*
    From YourTable
)A
where Rowid>@SkipCount --OFFSET
1
Barny

Dans SQL Server, vous utiliseriez TOP avec ROW_NUMBER ()

0
SQLMenace