¿Cómo implementar LIMIT con SQL Server?

Respuestas:

127

Iniciando SQL SERVER 2005, puede hacer esto ...

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;

o algo así para 2000 y versiones inferiores ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC
Leon Tayson
fuente
66
La segunda consulta falla si tiene, por ejemplo, 14 filas en la tabla. Le da las filas 5 a 14, pero desea las filas 11 a 14. En general, falla para la última "página" de un resultado, a menos que las filas totales sean múltiplos de ese tamaño de "página".
Bill Karwin
147
¡Una cosa tan simple debe volverse tan difícil para MS una vez más!
Martin
Esto es lo que funcionó para mí en SQL Server Management Studio 2017: SELECT * FROM [dbo]. <Inserte tableName aquí> DONDE @@ ROWCOUNT ENTRE <insert min here> y <insert max here>
Artorias2718
Simplemente fantástico, funciona de
maravilla
58

Clunky, pero funcionará.

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

La omisión de MSSQL de una cláusula LIMIT es criminal, IMO. No debería tener que hacer este tipo de solución poco clara.

ceejayoz
fuente
¿Tienes otra sugerencia para evitar esto?
Bigballs
Busqué mucho en Google la última vez que tuve que lidiar con MSSQL y esta fue la mejor solución que encontré. No es agradable, pero funciona.
ceejayoz 02 de
Esta solución solo funciona si el conjunto de resultados incluye una columna que es única. No es una solución general imitar LIMIT para cualquier consulta.
Bill Karwin
1
Estoy en un dilema similar en este momento ... Sin embargo, en mi caso estoy manguera ... Es aún más criminal cuando los llamados dba 'expertos' deciden que una clave única es innecesaria en una tabla ... CUALQUIER tabla ... ¡Ni siquiera traigas el tema de claves y restricciones foráneas!
Andrew Rollings
El problema con este es que no maneja muy bien las cláusulas WHERE ... Voy a probar tablas temporales, ya que no funciona para mí.
pasty desagradable
37

A partir de SQL SERVER 2012, puede usar la cláusula 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

Esto puede no funcionar correctamente cuando el pedido no es único.

Si la consulta se modifica a ORDER BY OrderDate, el conjunto de resultados devuelto no es el esperado.

usuario4047259
fuente
Usar 'con' solo necesita la mitad del tiempo para finalizar la consulta; vea la respuesta de @Leon Tayson. No tengo idea de lo que hizo Microsoft para hacerlo tan lento.
isHuman
1
¿Por qué esta no es la respuesta aceptada? ¡Estamos en 2018 por el amor de Dios!
Patrón
1
@Skipper a la derecha. el aceptado todavía funciona. Vamos a votar este para reflejar la actualización.
kronn
18

Esto es casi un duplicado de una pregunta que hice en octubre: emular la cláusula LIMIT de MySQL en Microsoft SQL Server 2000

Si está utilizando Microsoft SQL Server 2000, no hay una buena solución. La mayoría de las personas tienen que recurrir a capturar el resultado de la consulta en una tabla temporal con una IDENTITYclave primaria. Luego, consulte la columna de la clave principal utilizando una BETWEENcondición.

Si está utilizando Microsoft SQL Server 2005 o posterior, tiene una ROW_NUMBER()función, por lo que puede obtener el mismo resultado pero evitar la tabla temporal.

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;

También puede escribir esto como una expresión de tabla común como se muestra en la respuesta de @Leon Tayson .

Bill Karwin
fuente
ROW_NUMBER () OVER (ORDER BY) obtiene puntos por ser válido en ANSI SQL: 2003, aunque el soporte en DBMS que no sean SQL Server es muy irregular. Y es bastante torpe, por supuesto ...
bobince
@bobince: Resulta que Oracle, Microsoft SQL Server 2005, IBM DB2 y PostgreSQL 8.4 soportan todas las funciones de la ventana. Eso cubre una gran mayoría del mercado SQL. El soporte solo es irregular si usa MySQL, SQLite o una versión anterior de la base de datos anterior.
Bill Karwin
16

Así es como limito los resultados en MS SQL Server 2012:

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

NOTA: OFFSETsolo se puede usar con o en conjunto con ORDER BY.

Para explicar la línea de código OFFSET xx ROWS FETCH NEXT yy ROW ONLY

El xxes el número de registro / fila del que desea comenzar a extraer en la tabla, es decir: si hay 40 registros en la tabla 1, el código anterior comenzará a extraer de la fila 10.

El yyes el número de registros / filas que desea extraer de la tabla.

Para construir sobre el ejemplo anterior: Si la tabla 1 tiene 40 registros y comenzó a extraer de la fila 10 y tomar el siguiente conjunto de 10 ( yy). Eso significaría que el código anterior extraerá los registros de la tabla 1, comenzando en la fila 10 y terminando en 20. Por lo tanto, extrayendo las filas 10-20.

Consulte el enlace para obtener más información sobre OFFSET

Jeremy
fuente
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
Quassnoi
fuente
Bueno, acabo de comprobar que SQL Server resultó ser lo suficientemente inteligente como para detenerse en condiciones ROW_NUMBER (), si hay una columna indexada en la cláusula ORDER BY.
Quassnoi
9

La consulta de MySQL LIMIT sintácticamente es algo como esto:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

Esto se puede traducir a Microsoft SQL Server como

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

Ahora su consulta select * from table1 LIMIT 10,20será así:

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

fuente
2

Esta es una de las razones por las que trato de evitar usar MS Server ... pero de todos modos. A veces simplemente no tienes una opción (¡sí! ¡Y tengo que usar una versión desactualizada!).

Mi sugerencia es crear una tabla virtual:

De:

SELECT * FROM table

A:

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

Entonces solo consulta:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

Si se agregan o eliminan campos, la "fila" se actualiza automáticamente.

El principal problema con esta opción es que ORDER BY es fijo. Entonces, si desea un orden diferente, deberá crear otra vista.

ACTUALIZAR

Hay otro problema con este enfoque: si intenta filtrar sus datos, no funcionará como se esperaba. Por ejemplo, si haces:

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

WHERE se limita a aquellos datos que están en las filas entre 10 y 20 (en lugar de buscar en todo el conjunto de datos y limitar la salida).

lepe
fuente
1

Este es un enfoque de múltiples pasos que funcionará en 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
souLTower
fuente
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;
Julián Moreno
fuente
Fue una gran solución para mí.
Tyde
1

Deberías intentar. En la consulta a continuación, puede ver agrupar por, ordenar por, Omitir filas y limitar filas.

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
M danés
fuente
0
SELECT TOP 10 * FROM table;

Es lo mismo que

SELECT * FROM table LIMIT 0,10;

Aquí hay un artículo sobre la implementación de Limit en MsSQL Es una buena lectura, especialmente los comentarios.

Ólafur Waage
fuente
1
Gracias, pero quiero el registro entre 10 y 20, ¿hay alguna manera de hacerlo?
Bigballs
55
Esta respuesta no responde a la pregunta de origen, pero es útil si alguien como yo tiene que saber cómo obtener los primeros resultados y N llegó aquí a través de Google, etc ...
brianlmerritt
0

En SQL no existe una palabra clave LIMIT. Si solo necesita un número limitado de filas, debe usar una palabra clave TOP que sea similar a un LIMIT.

Mitul Panchal
fuente
0

Si su ID es un tipo de identificador único o su ID en la tabla no está ordenada, debe hacer lo siguiente a continuación.

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



El código será

seleccione * del límite 2,5
usuario3244012
fuente
0

mejor usar esto en MSSQLExpress 2017.

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

- Dando una columna [Count] y asignando a cada fila un recuento único sin ordenar algo, luego vuelva a seleccionar dónde puede proporcionar sus límites .. :)

usuario1308314
fuente
0

Una de las formas posibles de obtener resultados como se muestra a continuación, espero que esto ayude.

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
Pragnesh Karia
fuente
0

Manera fácil

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 es obligatorio

Turendu
fuente
-2

Si recuerdo correctamente (ha pasado un tiempo desde que utilicé SQL Server), puede usar algo como esto: (2005 y versiones posteriores)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20
Kris
fuente
SQL Server 2012: Mensaje 207, Nivel 16, Estado 1, Línea 5 Nombre de columna no válido 'RowNum'.
e-info128
Parece que tienes un error tipográfico en tu declaración en alguna parte. RowNum es el nombre que asignamos a la expresión. Publique su problema con la fuente y la comunidad lo ayudará
Kris
Esta no es una sintaxis válida. No puede hacer referencia en WHEREun alias definido en la misma SELECTcláusula de nivel .
ypercubeᵀᴹ