Como escrevo .Skip (1000) .Take (100) do LINQ em SQL puro?

93

Qual é o equivalente SQL do .Skip()método em LINQ?

Por exemplo: Eu gostaria de selecionar as linhas 1000-1100 de uma tabela de banco de dados específica.

Isso é possível apenas com SQL? Ou preciso selecionar a tabela inteira e encontrar as linhas na memória? Eu gostaria de evitar isso, se possível, uma vez que a mesa pode ser muito grande.

Raio
fonte

Respostas:

78

No SQL Server 2005 e superior, você pode usar a função ROW_NUMBER . por exemplo.

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 51 AND 60; --BETWEEN is inclusive
Dan Diplo
fonte
Veja o link em minha resposta para mais detalhes. stackoverflow.com/questions/1744802/…
Mike Atlas
ENTRE 51 e 60 - é inclusivo.
Drew Miller de
1
Mas isso primeiro selecionará todos e, a partir dessa seleção, pegará apenas 10, certo? Ou a primeira consulta / visualização já terá apenas 10?
Tadej
138

O SQL Server 2012 e superior adicionaram esta sintaxe:

SELECT *
FROM Sales.SalesOrderHeader 
ORDER BY OrderDate
OFFSET (@Skip) ROWS FETCH NEXT (@Take) ROWS ONLY
John Gietzen
fonte
11
Observe que você precisa usar ORDER BY ___ para usar o comando OFFSET .... não que você deva tentar paginar sem um pedido.
James Haug
Observe também que a 'nova' sintaxe estranhamente tem uma penalidade de desempenho linear com o @skip! A abordagem row_number NÃO tem isso (testado apenas na ordem indexada). Para lo @Skip menos cerca de 20, a nova sintaxe é mais rápida do que a abordagem row_number.
Eske Rahn
22

LINQ to SQL faz isso usando uma função de janela ROW_NUMBER:

  SELECT a,b,c FROM 
   (SELECT a,b,c, ROW_NUMBER() OVER (ORDER BY ...) as row_number
    FROM Table) t0
   WHERE to.row_number BETWEEN 1000 and 1100;

Isso funciona, mas a necessidade de fabricar o row_number do ORDER BY pode resultar na classificação da sua consulta no lado do servidor e causar problemas de desempenho. Mesmo quando um índice pode satisfazer o requisito ORDER BY, a consulta ainda precisa contar 1000 linhas antes de começar a retornar resultados. Com muita frequência, os desenvolvedores esquecem isso e apenas lançam um controle de paginação sobre uma tabela de 5 milhões de linhas e se perguntam por que a primeira página é retornada muito mais rápido do que a última ...

No entanto, usar ROW_NUMBER () é provavelmente o melhor equilíbrio entre facilidade de uso e bom desempenho, desde que você tenha certeza de evitar a classificação (a condição ORDER BY pode ser satisfeita por um índice).

Remus Rusanu
fonte
1
Obrigado pela informação de desempenho extra, terá que ter cuidado e testá-lo.
Ray
Testado e para minha tabela de meio milhão de linhas, a última página é cerca de 7 vezes mais lenta que a primeira página. Não é ideal, mas é aceitável para mim.
Ray
6

Tente este:

select * from [Table-Name] order by [Column-Name] 
offset [Skip-Count] rows
FETCH NEXT [Take-Count] rows only

Exemplo:

select * from Personals order by Id
offset 10 rows            --------->Skip 10
FETCH NEXT 15 rows only   --------->Take 15
Fereydoon Barikzehy
fonte
4

Faça isso:

Execute .Skip (1000) .Take (100) em um texto de dados LINQ to SQL e observe a saída SQL. Ele irá gerar uma instrução SQL para você que faz o que você está descrevendo.

Não será tão elegante, mas dá conta do recado.

Joseph
fonte
2
Não o que estava sendo perguntado.
RayLoveless,