2010-01-25 18 views
131

Dans PostgreSQL, il y a les mots-clés Limit et Offset qui permettent une pagination très facile des ensembles de résultats.Équivalent de LIMIT et OFFSET pour SQL Server?

Quelle est la syntaxe équivalente pour Sql Server?

+0

Pour SQL Server 2012, cette fonctionnalité est implémentée de manière simple. Voir [ma réponse] (http://stackoverflow.com/a/9261762/1045444) –

+0

Merci d'avoir posé cette question, nous sommes obligés de faire la transition de MySQL à MsSQL :( – Logikos

Répondre

112

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

;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 limite au cas où vous décidez de changer vos options de pagination (ou permettre à l'utilisateur de le faire).

Remarque: le paramètre doit utiliser l'indexation basée sur un seul pour cela plutôt que l'indexation normale basée sur zéro.

+14

Ancien maintenant Sql Server 2012 et versions ultérieures prennent en charge OFFSET/FETCH –

+25

@JoelCoehoorn Pas vieux, je viens d'être assigné au projet en utilisant SLQ Server 2008 ayant utilisé seulement mysql dans le passé ... – Cthulhu

+0

Ceci est assez bon mais doit être ajusté un peu 'WHERE RowNum> = (@Offset + 1 '' –

0

Dans le serveur SQL que vous utilisez TOP avec ROW_NUMBER()

7

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 
+0

Cela aurait dû être la réponse acceptée.Parfait –

2

Un autre exemple:

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; 
+13

J'ai supprimé votre discours de haine anti-microsoft. Ne discutez pas des guerres saintes ici; Il suffit de répondre et de poser des questions de manière non subjective. – Earlz

2

Il y a here quelqu'un dire sur cette fonctionnalité dans sql 2011, sa triste qu'ils choisissent un petit mot clé différent "OFFSET/fetch", mais ce ne est pas standart alors ok.

150

Cette fonctionnalité est désormais simplifiée dans SQL Server 2012. Cela fonctionne mais SQL server 2012 et après. Limite avec un décalage pour sélectionner 11 à 20 lignes dans le serveur sql:

SELECT email FROM emailTable 
WHERE id=3 
ORDER BY Id 
OFFSET 10 ROWS 
FETCH NEXT 10 ROWS ONLY; 

// offset - pas. de lignes sautées

// suivant - N ° requis des lignes suivantes

+4

Existe-t-il un équivalent de 'SQL_CALC_FOUND_ROWS' lorsque vous l'utilisez? – Petah

+1

@Petah @@ Rowcount vous donnera que je pense –

+3

cela aurait dû être la bonne réponse – Jeff

2

En ajoutant une légère variation à la solution d'Aaronaught, je paramétrise généralement le numéro de page (@PageNum) et la taille de la page (@PageSize). De cette façon, chaque événement click page envoie juste le numéro de page demandée 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 
21
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} 

Une note: Cette solution ne fonctionnera que dans SQL Server 2005 ou au-dessus, étant donné que cette était lorsque ROW_NUMBER() a été mis en œuvre.

+0

J'utilise cette requête depuis un petit moment maintenant et ça marche très bien alors merci pour ça. Je me demande juste ce que le "xx" représente? – Urbley

+0

la sous-requête nécessite un nom. comme je ne l'utilise pas il suffit de mettre xx là – jorgeu

+1

Le xx est juste un alias de table. Il pourrait être un peu plus clair si vous avez dit 'AS xx' –

2

Le plus proche que je pourrais faire est

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

Ce que je pense similaire à select * from [db].[dbo].[table] LIMIT 0, 10

+0

cela fonctionne merci. – oguzhan

0
select top (@TakeCount) * --FETCH NEXT 
from(
    Select ROW_NUMBER() OVER (order by StartDate) AS rowid,* 
    From YourTable 
)A 
where Rowid>@SkipCount --OFFSET 
1
@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

Puisque personne a fourni ce code encore:

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... 

Points importants:

  • ORDER BY doit être identique
  • @limit peut être remplacé par nombre de résultats à récupérer,
  • @offset est le nombre de résultats pour sauter
  • S'il vous plaît comparer les performances des solutions précédentes car ils peuvent être plus efficace
  • cette solution duplique les clauses where et order by, et fournira des résultats incorrects s'ils ne sont pas synchronisés
  • d'autre part order by est là explicitement si c'est ce qui est nécessaire
1

Pour moi, l'utilisation de OFFSET et FETCH ensemble était lent, donc j'ai utilisé une combinaison de TOP et OFFSET comme celui-ci (ce 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, donc pour utiliser TOP et OFFSET ensemble, vous devez le séparer avec une sous-requête.

Et si vous avez besoin d'utiliser SELECT DISTINCT alors la requête est comme:

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

Note: L'utilisation de SELECT ROW_NUMBER Distinct ne fonctionne pas pour moi.

+0

Je reçois "Un TOP ne peut pas être utilisé dans la même requête ou sous-requête qu'un OFFSET." – MichaelRushton

+0

Vous avez raison @MichaelRushton, ne peut pas être utilisé dans la même requête ou dans la même sous-requête, alors vous devez utiliser une sous-requête pour le séparer. Donc si vous avez le SQL comme 'SELECT TOP 20 id FROM table1 où id> 10 ordre par date OFFSET 20 rows', vous devez le transformer comme' SELECT TOP 20 * FROM (SELECT ID FROM table1 où id> 10 ordre par date OFFSET 20 RANGÉES) t1'. Je vais éditer ma réponse. Merci et excusez-moi mon anglais. – sebasdev

1
-- @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