Como implementar o LIMIT com o SQL Server?

Respostas:

127

Iniciando o SQL SERVER 2005, você pode fazer isso ...

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 algo assim para as versões 2000 e inferiores ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC
Leon Tayson
fonte
6
A segunda consulta falha se você tiver, por exemplo, 14 linhas na tabela. Ele fornece as linhas 5 a 14, mas você deseja as linhas 11 a 14. Em geral, falha na última "página" de um resultado, a menos que o total de linhas seja múltiplo do tamanho da "página".
Bill Karwin
147
Uma coisa tão simples precisa ser dificultada pelo MS mais uma vez!
Martin Martin
Aqui está o que funcionou para mim no SQL Server Management Studio de 2017: SELECT * FROM [dbo] <inserir tableName aqui> WHERE @@ ROWCOUNT ENTRE <inserir min aqui> e <inserção max aqui>.
Artorias2718
Apenas fantástico, ele funciona como charme no MS SQL Server 2017 select Statement
PatsonLeaner 13/06/19
58

Desajeitado, mas vai funcionar.

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

A omissão do MSSQL de uma cláusula LIMIT é criminal, IMO. Você não deveria ter que fazer esse tipo de solução alternativa.

ceejayoz
fonte
Você tem outra sugestão para contornar isso?
Bigballs
Pesquisei bastante no Google na última vez em que tive que lidar com o MSSQL e essa foi a melhor solução que encontrei. Não é agradável, mas funciona.
ceejayoz
Esta solução funciona apenas se o conjunto de resultados incluir uma coluna exclusiva. Não é uma solução geral imitar LIMIT para qualquer consulta.
Bill Karwin
1
Estou em um dilema semelhante no momento ... No entanto, no meu caso, estou sendo processado ... É ainda mais criminoso quando os chamados dba 'especialistas' decidem que uma chave única é desnecessária em uma tabela ... QUALQUER tabela ... Nem mencione o assunto de chaves e restrições estrangeiras!
Andrew Rollings
O problema com este é que ele não lida com as cláusulas WHERE muito bem ... Vou tentar tabelas temporárias, pois não está funcionando para mim.
pastosa desagradável
37

A partir do SQL SERVER 2012, você pode usar a 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

Isso pode não funcionar corretamente quando a ordem de não é exclusiva.

Se a consulta for modificada para ORDER BY OrderDate, o conjunto de resultados retornado não será o esperado.

user4047259
fonte
Usar 'with' precisa apenas de metade do tempo para concluir a consulta - veja a resposta de @Leon Tayson. Não faço ideia do que a Microsoft fez para tornar isso lento.
IsHuman #
1
Por que essa não é a resposta aceita? Estamos em 2018 pelo amor de Deus!
Skipper
1
@ Skipper certo. o aceito ainda funciona. Vamos votar novamente este para refletir a atualização.
Kronn
18

Isso é quase uma duplicata de uma pergunta que fiz em outubro: Emular a cláusula MySQL LIMIT no Microsoft SQL Server 2000

Se você estiver usando o Microsoft SQL Server 2000, não há uma boa solução. A maioria das pessoas precisa recorrer à captura do resultado da consulta em uma tabela temporária com uma IDENTITYchave primária. Em seguida, consulte a coluna da chave primária usando uma BETWEENcondição.

Se você estiver usando o Microsoft SQL Server 2005 ou posterior, terá uma ROW_NUMBER()função, para obter o mesmo resultado, mas evite a tabela temporária.

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;

Você também pode escrever isso como uma expressão de tabela comum, como mostra a resposta de @Leon Tayson .

Bill Karwin
fonte
ROW_NUMBER () OVER (ORDER BY) obtém pontos por ser válido no ANSI SQL: 2003, embora o suporte em DBMSs diferentes do SQL Server seja muito irregular. E é muito desajeitado, é claro ...
bobince
@bobince: Acontece que Oracle, Microsoft SQL Server 2005, IBM DB2 e PostgreSQL 8.4 suportam todas as funções da janela. Isso cobre uma grande maioria do mercado de SQL. O suporte é apenas irregular se você usar MySQL, SQLite ou uma versão antiga dos bancos de dados acima.
Bill Karwin
16

É assim que limito os resultados no MS SQL Server 2012:

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

NOTA: OFFSETsó pode ser usado com ou em conjunto com ORDER BY.

Para explicar a linha de código OFFSET xx ROWS FETCH NEXT yy ROW ONLY

A xxé o número de registro / linha que deseja começar a puxar a partir da tabela, ou seja: se houver 40 registros na tabela 1, o código acima irá começar a puxar da linha 10.

O yyé o número de registros / linhas que você deseja extrair da tabela.

Para desenvolver o exemplo anterior: Se a tabela 1 possui 40 registros e você começou a puxar da linha 10 e pegue o conjunto NEXT de 10 ( yy). Isso significa que o código acima extrairá os registros da tabela 1, iniciando na linha 10 e terminando em 20. Assim, extrair as linhas 10 - 20.

Confira o link para obter mais informações sobre OFFSET

Jeremy
fonte
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
fonte
Bem, acabei de verificar, o SQL Server mostrou-se inteligente o suficiente para parar nas condições ROW_NUMBER (), se houver uma coluna indexada na cláusula ORDER BY.
Quassnoi 02/03/09
9

A consulta Sintatisticamente MySQL LIMIT é algo como isto:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

Isso pode ser traduzido para o 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

Agora sua consulta select * from table1 LIMIT 10,20 será assim:

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

fonte
2

Esta é uma das razões pelas quais tento evitar o uso do MS Server ... mas mesmo assim. Às vezes você simplesmente não tem uma opção (yei! E eu tenho que usar uma versão desatualizada !!).

Minha sugestão é criar uma tabela virtual:

De:

SELECT * FROM table

Para:

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

Em seguida, basta consultar:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

Se os campos forem adicionados ou removidos, "linha" é atualizada automaticamente.

O principal problema com esta opção é que ORDER BY foi corrigido. Portanto, se você quiser uma ordem diferente, precisará criar outra exibição.

ATUALIZAR

Há outro problema com essa abordagem: se você tentar filtrar seus dados, eles não funcionarão conforme o esperado. Por exemplo, se você fizer:

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

WHERE fica limitado aos dados que estão nas linhas entre 10 e 20 (em vez de pesquisar todo o conjunto de dados e limitar a saída).

lepe
fonte
1

Essa é uma abordagem de várias etapas que funcionará no 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
fonte
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;
Julian Moreno
fonte
Foi uma ótima solução para mim.
Tyde
1

Deve tentar. Na consulta abaixo, você pode ver agrupar, ordenar, Ignorar linhas e limitar linhas.

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 dinamarquês
fonte
0
SELECT TOP 10 * FROM table;

É o mesmo que

SELECT * FROM table LIMIT 0,10;

Aqui está um artigo sobre a implementação do Limit no MsSQL. É uma boa leitura, especialmente os comentários.

Ólafur Waage
fonte
1
Obrigado, mas eu quero o disco entre 10 e 20, existe uma maneira de fazer isso?
Bigballs 02/03/09
5
Essa resposta não responde à pergunta origem, mas é útil se alguém como eu precisa saber como obter os primeiros resultados N e chegou aqui através do google etc ...
brianlmerritt
0

No SQL, não existe uma palavra-chave LIMIT. Se você precisar apenas de um número limitado de linhas, use uma palavra-chave TOP que seja semelhante a um LIMIT.

Mitul Panchal
fonte
0

Se seu ID for do tipo identificador único ou se não for classificado na tabela, faça o seguinte abaixo.

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



O código será

selecione * do limite 2,5
user3244012
fonte
0

melhor usar isso no 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 a uma coluna [Count] e atribuindo a cada linha uma contagem única sem solicitar algo e selecione novamente onde você pode fornecer seus limites .. :)

user1308314
fonte
0

Uma das maneiras possíveis de obter resultados como abaixo, espero que isso ajude.

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

Jeito 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 é obrigatório

Turendu
fonte
-2

Se bem me lembro (já faz um tempo desde que me envolvi com o SQL Server), talvez você possa usar algo assim: (2005 e posteriores)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20
Kris
fonte
SQL Server 2012: Mensagem 207, Nível 16, Estado 1, Linha 5 Nome da coluna inválido 'RowNum'.
e-info128
parece que você tem um erro de digitação em sua declaração em algum lugar. RowNum é o nome que atribuímos à expressão. Publique o seu problema com a fonte ea comunidade irá ajudá-lo
Kris
Esta não é uma sintaxe válida. Você não pode fazer referência a WHEREum alias definido na mesma SELECTcláusula de nível .
ypercubeᵀᴹ