Comment implémenter LIMIT avec SQL Server?


130

J'ai cette requête avec MySQL:

select * from table1 LIMIT 10,20

Comment puis-je faire cela avec SQL Server?


duplication possible de LIMIT 10..20 dans SQL Server
assylias

13
Puisque cette question a été posée en premier, l'autre question ne serait-elle pas le double?
Tab Alleman

Réponses:


127

À partir de SQL SERVER 2005, vous pouvez le faire ...

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 10 AND 20;

ou quelque chose comme ça pour les versions 2000 et inférieures ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC

6
La 2ème requête échoue si vous avez par exemple 14 lignes dans le tableau. Il vous donne les lignes 5 à 14, mais vous voulez les lignes 11 à 14. En général, il échoue pour la dernière «page» d'un résultat, à moins que le nombre total de lignes soit un multiple de cette taille de «page».
Bill Karwin

147
Une chose aussi simple doit encore être rendue si difficile par MS!
Martin le

Voici ce qui a fonctionné pour moi dans SQL Server Management Studio 2017: SELECT * FROM [dbo]. <Insert tableName here> WHERE @@ ROWCOUNT BETWEEN <insert min here> and <insert max here>
Artorias2718

Tout simplement fantastique, cela fonctionne comme un charme dans MS SQL Server 2017 Select Statement
PatsonLeaner

58

Clunky, mais ça marchera.

SELECT TOP 10 * FROM table WHERE id NOT IN (SELECT TOP 10 id FROM table ORDER BY id) FROM table ORDER BY id

L'omission par MSSQL d'une clause LIMIT est criminelle, IMO. Vous ne devriez pas avoir à faire ce genre de solution de contournement kludgy.


Avez-vous une autre suggestion pour contourner cela?
Bigballs

J'ai fait beaucoup de recherches sur Google la dernière fois que j'ai eu affaire à MSSQL et c'était la meilleure solution que j'ai trouvée. Pas agréable, mais ça marche.
ceejayoz

Cette solution ne fonctionne que si le jeu de résultats comprend une colonne unique. Ce n'est pas une solution générale pour imiter LIMIT pour une requête.
Bill Karwin

1
Je suis dans un dilemme similaire en ce moment ... Cependant, dans mon cas, je suis arrosé ... C'est encore plus criminel quand des dba dits `` experts '' décident qu'une clé unique n'est pas nécessaire dans une table ... ... N'abordez même pas le sujet des clés étrangères et des contraintes!
Andrew Rollings

Le problème avec celui-ci est qu'il ne gère pas très bien les clauses WHERE ... Je vais essayer les tables temporaires, car cela ne fonctionne pas pour moi.
méchant pâteux

37

À partir de SQL SERVER 2012, vous pouvez utiliser la clause OFFSET FETCH:

USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader 
ORDER BY SalesOrderID
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;
GO

http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx

Cela peut ne pas fonctionner correctement lorsque la commande par n'est pas unique.

Si la requête est modifiée en ORDER BY OrderDate, le jeu de résultats renvoyé n'est pas celui attendu.


L'utilisation de 'avec' ne prend que la moitié du temps pour terminer l'interrogation - voir la réponse de @Leon Tayson. Je n'ai aucune idée de ce que Microsoft a fait pour le rendre aussi lent.
isHuman le

1
Pourquoi n'est-ce pas la réponse acceptée? Nous sommes en 2018 pour pleurer à haute voix!
Skipper

1
@Skipper à droite. l'accepté fonctionne toujours. Mettons juste celui-ci au vote pour refléter la mise à jour.
kronn

18

C'est presque le double d'une question que j'ai posée en octobre: émuler la clause MySQL LIMIT dans Microsoft SQL Server 2000

Si vous utilisez Microsoft SQL Server 2000, il n'y a pas de bonne solution. La plupart des gens doivent recourir à la capture du résultat de la requête dans une table temporaire avec une IDENTITYclé primaire. Puis interrogez la colonne de clé primaire à l'aide d'unBETWEEN condition.

Si vous utilisez Microsoft SQL Server 2005 ou une version ultérieure, vous disposez d'une ROW_NUMBER()fonction, vous pouvez donc obtenir le même résultat, mais évitez la table temporaire.

SELECT t1.*
FROM (
    SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
    FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN @offset+1 AND @offset+@count;

Vous pouvez également l'écrire comme une expression de table commune comme indiqué dans la réponse de @Leon Tayson .


ROW_NUMBER () OVER (ORDER BY) obtient des points pour être valide dans ANSI SQL: 2003, bien que la prise en charge dans les SGBD autres que SQL Server soit très inégale. Et c'est assez maladroit bien sûr ...
bobince

@bobince: Il s'avère qu'Oracle, Microsoft SQL Server 2005, IBM DB2 et PostgreSQL 8.4 prennent toutes en charge les fonctions de la fenêtre. Cela couvre une grande majorité du marché SQL. Le support n'est irrégulier que si vous utilisez MySQL, SQLite ou une ancienne version de la base de données ci-dessus.
Bill Karwin

16

Voici comment je limite les résultats dans MS SQL Server 2012:

SELECT * 
FROM table1
ORDER BY columnName
  OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

REMARQUE: OFFSETne peut être utilisé qu'avec ou en tandem pourORDER BY .

Pour expliquer la ligne de code OFFSET xx ROWS FETCH NEXT yy ROW ONLY

le xx est le numéro d'enregistrement / de ligne à partir duquel vous souhaitez commencer à extraire dans la table, c'est-à-dire: S'il y a 40 enregistrements dans le tableau 1, le code ci-dessus commencera à extraire à partir de la ligne 10.

le yy est le nombre d'enregistrements / lignes que vous souhaitez extraire de la table.

Pour construire sur l'exemple précédent: Si la table 1 contient 40 enregistrements et que vous avez commencé à extraire de la ligne 10 et à saisir l'ensemble NEXT de 10 (yy ). Cela signifierait que le code ci-dessus extraira les enregistrements de la table 1 à partir de la ligne 10 et se terminant à 20. Tirant ainsi les lignes 10 à 20.

Consultez le lien pour plus d'informations sur OFFSET


12
SELECT  *
FROM    (
        SELECT  TOP 20
                t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
        FROM    table1 t
        ORDER BY
                field1
        ) t
WHERE   rn > 10

Eh bien, je viens de vérifier, SQL Server s'est avéré assez intelligent pour s'arrêter sur les conditions ROW_NUMBER (), s'il y a une colonne indexée dans la clause ORDER BY.
Quassnoi

9

Syntaxiquement, la requête MySQL LIMIT est quelque chose comme ceci:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

Cela peut être traduit dans Microsoft SQL Server comme

SELECT * FROM 
(
    SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table
) a
WHERE rnum > OFFSET

Maintenant, votre requête select * from table1 LIMIT 10,20sera comme ceci:

SELECT * FROM 
(
    SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table1
) a
WHERE rnum > 10 

2

C'est l'une des raisons pour lesquelles j'essaie d'éviter d'utiliser MS Server ... mais quand même. Parfois, vous n'avez tout simplement pas d'option (yei! Et je dois utiliser une version obsolète !!).

Ma suggestion est de créer une table virtuelle:

De:

SELECT * FROM table

À:

CREATE VIEW v_table AS    
    SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table

Ensuite, interrogez simplement:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

Si des champs sont ajoutés ou supprimés, la "ligne" est mise à jour automatiquement.

Le principal problème avec cette option est que ORDER BY est résolu. Donc, si vous voulez un ordre différent, vous devrez créer une autre vue.

METTRE À JOUR

Il y a un autre problème avec cette approche: si vous essayez de filtrer vos données, cela ne fonctionnera pas comme prévu. Par exemple, si vous faites:

SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20

WHERE devient limité aux données qui sont dans les lignes entre 10 et 20 (au lieu de rechercher l'ensemble de données et de limiter la sortie).


1

Il s'agit d'une approche en plusieurs étapes qui fonctionnera dans SQL2000.

-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)

INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria

Select * FROM #foo where rowID > 10

1
SELECT 
    * 
FROM 
    (
        SELECT 
            top 20              -- ($a) number of records to show
            * 
        FROM
            (
                SELECT 
                    top 29      -- ($b) last record position
                    * 
                FROM 
                    table       -- replace this for table name (i.e. "Customer")
                ORDER BY 
                    2 ASC
            ) AS tbl1 
        ORDER BY 
            2 DESC
    ) AS tbl2 
ORDER BY 
    2 ASC;

-- Examples:

-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;

-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;

-- To calculate $b:
-- $b = ($a + position) - 1

-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;

C'était une excellente solution pour moi.
Tyde

1

Dois essayer. Dans la requête ci-dessous, vous pouvez voir le groupe par, l'ordre par, ignorer les lignes et limiter les lignes.

select emp_no , sum(salary_amount) from emp_salary
Group by emp_no 
ORDER BY emp_no 
OFFSET 5 ROWS       -- Skip first 5 
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows

0
SELECT TOP 10 * FROM table;

Est le même que

SELECT * FROM table LIMIT 0,10;

Voici un article sur l'implémentation de Limit dans MsSQL C'est une bonne lecture, spécialement les commentaires.


1
Merci, mais je veux le record entre 10 et 20, il y a un moyen de le faire?
Bigballs

5
Cette réponse ne répond pas à la question d'origine, mais c'est utile si quelqu'un comme moi a besoin de savoir comment obtenir les premiers résultats N et arriver ici via google etc ...
brianlmerritt

0

En SQL, il n'existe pas de mot clé LIMIT. Si vous n'avez besoin que d'un nombre limité de lignes, vous devez utiliser un mot-clé TOP similaire à LIMIT.


0

Si votre identifiant est de type identifiant unique ou que votre identifiant dans la table n'est pas trié, vous devez procéder comme suit.

select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5



Le code sera

sélectionner * à partir de la limite 2,5

0

mieux utiliser cela dans MSSQLExpress 2017.

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;

--Donner une colonne [Count] et attribuer à chaque ligne un comptage unique sans ordonner quelque chose, puis re-sélectionner où vous pouvez fournir vos limites .. :)


0

L'un des moyens possibles d'obtenir le résultat ci-dessous, espérons que cela vous aidera.

declare @start int
declare @end int
SET @start = '5000';  -- 0 , 5000 ,
SET @end = '10000'; -- 5001, 10001
SELECT * FROM ( 
  SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
 ) a WHERE a.row > @start and a.row <= @end

0

Moyen facile

MYSQL:

SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'

MSSQL:

SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset' 
ROWS FETCH NEXT 'per_page' ROWS ONLY

ORDER BY est obligatoire


-2

Si je me souviens bien (cela fait un moment que je n'ai pas utilisé SQL Server), vous pourrez peut-être utiliser quelque chose comme ceci: (2005 et plus)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20

SQL Server 2012: Msg 207, niveau 16, état 1, ligne 5 Nom de colonne non valide 'RowNum'.
e-info128

on dirait que vous avez une faute de frappe dans votre déclaration quelque part. RowNum est le nom que nous attribuons à l'expression. Postez votre problème avec la source et la communauté vous aidera
Kris

Ce n'est pas une syntaxe valide. Vous ne pouvez pas référencer dans WHEREun alias défini dans la même SELECTclause de niveau .
ypercubeᵀᴹ
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.