2009-06-09 19 views
131

estoy tratando de hacer algo como:LÍMITE 10..20 en SQL Server

SELECT * FROM table LIMIT 10,20 

o

SELECT * FROM table LIMIT 10 OFFSET 10 

pero utilizando SQL Server

La única solution I found parece una exageración:

SELECT * FROM ( 
    SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases 
) a WHERE row > 5 and row <= 10 

También found:

SELECT TOP 10 * FROM stuff; 

... pero no es lo que quiero hacer ya que no puedo especificar el límite inicial.

¿Hay alguna otra manera de hacerlo?

Además, solo curiosidad, ¿hay alguna razón por la cual SQL Server no admite la función LIMIT o algo similar? No quiero ser malo, pero eso realmente suena como algo que un DBMS necesita ... Si lo hace, ¡entonces lo siento por ser tan ignorante! He estado trabajando con MySQL y SQL + durante los últimos 5 años, así que ...

+1

El uso de un CTE de 'ROW_NUMBER()' y limitando con 'top' para el ancho del rango y una condición 'WHERE' para un límite del rango es lo mejor que he podido lograr. También he notado un rendimiento mucho mejor si la cláusula 'TOP' usa un literal en lugar de variable – Jodrell

+0

El problema con cualquier solución que implique el ROW_NUMBER() es que si no sabes de antemano qué columnas tendrás, y tú tienen uniones, y las tablas unidas tienen el mismo nombre de columna, obtendrás una "La columna 'xxx' fue especificada varias veces". Esto no es tan raro como podría sonar inicialmente. Yo uso Dapper, y todas mis tablas tienen una columna Id. Dapper se divide y mapea en eso, así que no quiero cambiarles el nombre, pero no puedo usar el alias SELECT * FROM ([consulta original]). ¡Todavía no he encontrado una solución! –

+0

Posible duplicado de [Cómo implementar LIMIT con Microsoft SQL Server?] (Https://stackoverflow.com/questions/603724/how-to-implement-limit-with-microsoft-sql-server) – kenorb

Respuesta

86

La cláusula LIMIT no es parte del SQL estándar. Es compatible como una extensión de proveedor de SQL por MySQL, PostgreSQL y SQLite.

Otras marcas de base de datos pueden tener características similares (por ejemplo, TOP en Microsoft SQL Server), pero estas no siempre funcionan de manera idéntica.

Es difícil de usar TOP en Microsoft SQL Server para imitar la cláusula LIMIT. Hay casos en los que simplemente no funciona.

La solución que mostró, utilizando ROW_NUMBER(), está disponible en Microsoft SQL Server 2005 y posterior. Esta es la mejor solución (por ahora) que funciona únicamente como parte de la consulta.

Otra solución es utilizar TOP a buscar el primer recuento + desplazamiento filas, y luego utilizar la API de buscar más allá del primer desplazamiento filas.

Consulte también:

6

Desafortunadamente, el ROW_NUMBER() es lo mejor que puedes hacer. En realidad es más correcto, porque los resultados de una cláusula limit o top realmente no tienen significado sin respeto a algún orden específico. Pero todavía es un dolor hacerlo.

Actualización: Sql Server 2012 agrega una característica similar a limit a través de las palabras clave OFFSET y FETCH.

+0

@Joel: ¿Puedes explicar por qué ROW_NUMBER() no puede numerar las filas de la forma en que salen de ORDER BY? Siempre me he preguntado por qué el "OVER (ORDER BY nombre)" es obligatorio, pero creo que hay una buena razón para ello. O al menos * a * razón. – Tomalak

+3

porque no existe tal orden sin una orden por cláusula. Obtiene el orden en el que los registros estuvieron disponibles para el servidor, y eso podría cambiar de la solicitud de consulta a la solicitud de consulta. –

+0

Pero me refería explícitamente a una cláusula ORDER BY. Supongamos que la consulta en sí tiene uno: ¿por qué no puede ROW_NUMBER() simplemente eso? Quiero decir, ¿cuál es la razón interna de la base de datos que me obliga a cambiar la consulta en dos lugares si quiero obtener una porción de ella en un orden diferente? – Tomalak

31

como lo encontró, este es el método preferido de SQL Server:

SELECT * FROM ( 
    SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases 
) a WHERE a.row > 5 and a.row <= 10 
+0

¿Por qué el 'a' después de la selección interna?Supongo que le está dando a la selección interna un alias, pero parece que nunca la usa ... ¿Debería hacer 'a.row' en lugar de' row'? – Lucas

+3

@Lucas, debe poner un alias después de la tabla derivada '()', pero lo dejará ir si olvida usarlo para referirse a las columnas. Lo arreglé sin embargo ... –

+0

gracias, lo encontré de la manera difícil (traté de dejar el alias). – Lucas

5

¿Qué tal esto?

SET ROWCOUNT 10 

SELECT TOP 20 * 
FROM sys.databases 
ORDER BY database_id DESC 

Le muestra las últimas 10 filas de las primeras 20 filas. Una desventaja es que el orden se invierte, pero, al menos, es fácil de recordar.

+4

¿Qué pasa si solo hay 14 filas en la tabla? Obtiene las filas 14 hasta 5, que no es lo mismo que las filas devueltas por LIMIT 10 OFFSET 10 (deben ser las filas 14 hasta 11). –

1
SELECT TOP 10 * 
FROM TABLE 
WHERE IDCOLUMN NOT IN (SELECT TOP 10 IDCOLUMN FROM TABLE) 

debe dar registros 11-20. Probablemente no sea demasiado eficiente si se incrementa para obtener más páginas, y no estoy seguro de cómo podría verse afectado por el pedido. Podría tener que especificar esto en ambas instrucciones WHERE.

105

Para SQL Server 2012 + you can use.

SELECT * 
FROM  sys.databases 
ORDER BY name 
OFFSET 5 ROWS 
FETCH NEXT 5 ROWS ONLY 
+7

SQl Server 2012 requiere especificar ORDER BY cuando usa OFFSET 5 ROWS FETCH NEXT 5 ROWS SOLAMENTE mientras MySql y SQLite no requieren ORDER BY cuando usa LIMIT 5,5 – qub1n

+4

@qub1n - MySQL [no garantiza] (http : //stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination), sin embargo, las filas que obtendrá en ese caso. –

+3

¿Tiene que usar 'offset', o puede dejar esa línea (suponiendo que no desea una compensación)? – Cullub

7

Si está utilizando SQL Server 2012+ voto para Martin Smith's answer y utilizar los OFFSET y FETCH NEXT extensiones a ORDER BY,

Si tienes la mala suerte de estar pegado a una versión anterior, se podría hacer algo como esto,

WITH Rows AS 
(
    SELECT 
       ROW_NUMBER() OVER (ORDER BY [dbo].[SomeColumn]) [Row] 
      , * 
     FROM 
       [dbo].[SomeTable] 
) 
SELECT TOP 10 
      * 
    FROM 
     Rows 
    WHERE Row > 10 

creo que es equivalente a functionaly

SELECT * FROM SomeTable LIMIT 10 OFFSET 10 ORDER BY SomeColumn 

y la mejor manera de realizar Sé de hacerlo en TSQL, antes de MS SQL 2012.


Si hay muchas filas que puede obtener un mejor rendimiento usando una tabla temporal en lugar de un CTE.

+0

Upvoted para señalar la respuesta de Martin Smith (y vincularla) mientras proporciona una solución anterior a 2012. También para el consejo de la tabla temporal porque está correcto :) – fujiiface

0
select * from (select id,name,ROW_NUMBER() OVER (ORDER BY id asc) as row 
from tableName1) tbl1 
where tbl1.row>=10 and tbl1.row<=15 

imprimirá filas de 10 a 15.

0

Hasta ahora, este formato es lo que está funcionando para mí (no el mejor rendimiento sin embargo):

SELECT TOP {desired amount of rows} * 
FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY {order columns} asc)__row__ FROM {table})tmp 
WHERE __row__ > {offset row count} 

Una nota en la cara, paginar sobre datos dinámicos puede conducir a resultados extraños/inesperados.

0

De la documentación en línea del servidor MS SQL (http://technet.microsoft.com/en-us/library/ms186734.aspx ), este es el ejemplo que he probado y funciona, para recuperar un conjunto específico de filas.ROW_NUMBER requiere un exceso, pero se puede pedir por lo que quiera:

WITH OrderedOrders AS 
(
    SELECT SalesOrderID, OrderDate, 
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber 
    FROM Sales.SalesOrderHeader 
) 
SELECT SalesOrderID, OrderDate, RowNumber 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 50 AND 60; 
1

Una buena manera es crear un procedimiento:

create proc pagination (@startfrom int ,@endto int) as 
SELECT * FROM ( 
    SELECT *, ROW_NUMBER() OVER (ORDER BY name desc) as row FROM sys.databases 
) a WHERE a.row > @startfrom and a.row <= @endto 

como límite de 0,2 ////// ///////// ejecutar la paginación 0,4

0

Usar todos los servidores SQL: ; con TBL como (SELECT ROW_NUMBER() sobre (ordenado por (seleccione 1)) como rowIndex, * de la tabla) seleccione top 10 * desde tbl donde RowIndex> = 10

-3
SELECT * FROM users WHERE Id Between 15 and 25 

se imprimirá de 15 a 25 como como límite en MySQL

+2

¿Qué pasa si el usuario borró un registro entre 15 y 25? –

1

Sólo por la solución de registro que funciona en la mayoría de los motores de bases de datos, aunque podría no ser el más eficiente:

Select Top (ReturnCount) * 
From (
    Select Top (SkipCount + ReturnCount) * 
    From SourceTable 
    Order By ReverseSortCondition 
) ReverseSorted 
Order By SortCondition 

Pelase Nota: la última página aún contendría las filas ReturnCount sin importar qué es SkipCount. Pero eso podría ser algo bueno en muchos casos.

1

El equivalente de límite se establece ROWCOUNT, pero si quieres la paginación genérica que es mejor escribir una consulta como esta:

;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