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

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.


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.


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 .


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


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

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 

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


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

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;

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

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.


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.


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

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


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

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


-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

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ᵀᴹ
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.