2009-06-09 8 views
131

Próbuję zrobić coś takiego:LIMIT 10..20 w SQL Server

SELECT * FROM table LIMIT 10,20 

lub

SELECT * FROM table LIMIT 10 OFFSET 10 

ale przy użyciu SQL Server

Jedynym solution I found wygląda jak overkill:

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

Ja też found:

SELECT TOP 10 * FROM stuff; 

... ale to nie to, co chcę zrobić, ponieważ nie można określić limit początkowy.

Czy jest inny sposób, aby to zrobić?

Co ciekawe, czy istnieje powód, dla którego serwer SQL nie obsługuje funkcji LIMIT lub czegoś podobnego? Nie chcę być wredny, ale to naprawdę brzmi jak coś, czego DBMS potrzebuje ... Jeśli tak, to przepraszam za bycie tak nieświadomym! Pracuję z MySQL i SQL + przez ostatnie 5 lat, więc ...

+1

Korzystanie CTE dla 'ROW_NUMBER()' oraz ograniczenie z 'TOP' dla osób szerokość zakresu i warunek "WHERE" dla granicy zakresu jest najlepszy, jaki udało mi się osiągnąć. Zauważyłem także znacznie lepszą wydajność, jeśli klauzula 'TOP' używa literału zamiast zmiennej – Jodrell

+0

Problem z jakimkolwiek rozwiązaniem obejmującym ROW_NUMBER() jest taki, że jeśli nie wiesz z góry, jakie kolumny będziesz miał, a ty mieć złączenia, a połączone tabele mają tę samą nazwę kolumny, otrzymasz "Kolumna" xxx "została określona wiele razy". To nie jest tak rzadkie, jak mogłoby początkowo brzmieć. Używam Dappera, a moje tabele mają kolumnę Id. Dapper dzieli i mapuje na tym, więc nie chcę ich zmieniać, ale nie mogę użyć aliasu SELECT * FROM ([original query]). Jeszcze nie znalazłem rozwiązania! –

+0

Możliwy duplikat [Jak wdrożyć LIMIT z Microsoft SQL Server?] (Https://stackoverflow.com/questions/603724/how-to-implement-limit-with-microsoft-sql-server) – kenorb

Odpowiedz

86

Klauzula LIMIT nie jest częścią standardowego SQL. Jest obsługiwany jako rozszerzenie dostawcy SQL przez MySQL, PostgreSQL i SQLite.

Inne marki bazy danych mogą mieć podobne funkcje (np. TOP w Microsoft SQL Server), ale te nie zawsze działają identycznie.

Trudno używać TOP w Microsoft SQL Server do naśladowania klauzuli LIMIT. Są przypadki, w których to po prostu nie działa.

Rozwiązanie, które pokazałeś, używając ROW_NUMBER(), jest dostępne w Microsoft SQL Server 2005 i nowszych wersjach. To najlepsze rozwiązanie (na razie), które działa wyłącznie jako część zapytania.

Innym rozwiązaniem jest użycie TOP pobrać pierwszy liczbę + przesunięcia rzędy, a następnie za pomocą API poszukiwania po pierwszym przesunięcie wierszy.

Zobacz także:

6

Niestety, ROW_NUMBER() to najlepsze, co możesz zrobić. Właściwie jest to bardziej poprawne, ponieważ wyniki klauzuli limit lub top nie mają właściwie znaczenia bez poszanowania określonej kolejności. Ale wciąż jest to trudne.

Aktualizacja: Sql Server 2012 dodaje funkcję podobną do limit poprzez słowa kluczowe OFFSET i FETCH.

+0

@Joel: Czy możesz wyjaśnić, dlaczego funkcja ROW_NUMBER() nie może numerować wierszy w taki sposób, w jaki wychodzi z ORDER BY? Zawsze zastanawiałem się, dlaczego "PONADTO (ORDER BY name)" jest obowiązkowe, ale myślę, że istnieje ku temu dobry powód. A przynajmniej powód * a *. – Tomalak

+3

, ponieważ nie ma czegoś takiego jak zamówienie bez klauzuli zamówienia. Otrzymujesz kolejność, w jakiej rekordy były dostępne dla serwera, i to może zmienić z zapytania zapytania na żądanie zapytania. –

+0

Ale wyraźnie odwoływałem się do klauzuli ORDER BY. Załóżmy, że samo zapytanie ma jeden - dlaczego nie może ROW_NUMBER() tylko to? Chodzi mi o to, jaki jest wewnętrzny powód DB, który zmusza mnie do zmiany zapytania w dwóch miejscach, jeśli chcę dostać kawałek w innej kolejności? – Tomalak

31

jak stwierdzono, jest to sposób preferowany serwer SQL:

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

Dlaczego "a" po wewnętrznej selekcji?Zakładam, że dajesz wewnętrzny wybór aliasu, ale nigdy go nie używasz ... Czy powinieneś zrobić 'a.row' zamiast tylko' row'? – Lucas

+3

@Lucas, musisz umieścić alias po tabeli wyprowadzonej '()', ale pozwoli to odejść, jeśli zapomnisz użyć jej do odnoszenia się do kolumn. Naprawiłem to jednak ... –

+0

dzięki, znalazłem to na własnej skórze (próbowałem zostawić alias). – Lucas

5

Jak na ten temat?

SET ROWCOUNT 10 

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

Daje ci ostatnie 10 rzędów z pierwszych 20 rzędów. Wadą jest to, że kolejność jest odwrotna, ale przynajmniej jest łatwa do zapamiętania.

+4

Co, jeśli w tabeli są tylko 14 wierszy? Otrzymujesz rzędy 14 w dół do 5, co nie jest tym samym, co wiersze zwrócone przez LIMIT 10 OFFSET 10 (powinny być wiersze 14 w dół do 11). –

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

powinien dać rekordy 11-20. Prawdopodobnie nie jest zbyt wydajna, jeśli inkrementuje się, by uzyskać kolejne strony, i nie jest pewien, w jaki sposób może wpłynąć na zamówienie. Może to wymagać w obu instrukcjach WHERE.

105

Dla serwera SQL 2012 + you can use.

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

SQl Server 2012 wymaga określenia ORDER BY, gdy korzystasz z OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY, podczas gdy MySql i SQLite nie wymagają ORDER BY, gdy używasz LIMIT 5,5 – qub1n

+4

@ qub1n - MySQL [nie gwarantuje] (http : //stackoverflow.com/questions/6314879/does-limit-offset-length-require-order-by-for-pagination) jakie wiersze otrzymasz w tym przypadku. –

+3

Czy musisz używać 'offset', czy możesz wyjść z tej linii (zakładając, że nie chcesz offsetu)? – Cullub

7

Jeśli używasz SQL Server 2012+ głos na Martin Smith's answer i użyj OFFSET i FETCH NEXT rozszerzenia ORDER BY,

Jeśli jesteś na tyle niefortunne być zatrzymany z wcześniejszej wersji, można zrobić coś takiego to,

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

wierzę jest funkcjonalnie równoważne

SELECT * FROM SomeTable LIMIT 10 OFFSET 10 ORDER BY SomeColumn 

a najlepszym sposobem wykonywania Znam to robić w TSQL, zanim MS SQL 2012.


Jeśli istnieje bardzo wiele wierszy można uzyskać lepsze wyniki stosując temp tabeli zamiast CTE.

+0

Rewizja za wskazanie odpowiedzi Martina Smitha (i powiązanie z nią) przy jednoczesnym zapewnieniu rozwiązania sprzed 2012 roku. Również dla porady tabeli temp, ponieważ masz rację :) – 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 

drukuje wiersze od 10 do 15.

0

Dotychczas ten format jest co działa dla mnie (nie najlepsza wydajność choć):

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} 

notatkę na boku, Dzielenie stron na dane dynamiczne może prowadzić do dziwnych/nieoczekiwanych rezultatów.

0

Z dokumentacji online serwera MS SQL Server (http://technet.microsoft.com/en-us/library/ms186734.aspx ), tutaj jest ich przykład, który przetestowałem i działa, do pobierania określonego zestawu wierszy.ROW_NUMBER wymaga skończy, ale można zamówić przez cokolwiek chcesz:

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

Dobrym sposobem jest stworzenie procedury:

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 

podobnie jak limitem 0,2 ////// ///////// wykonać paginacji 0,4

0

Wykorzystanie wszystkich serwerów SQL: ; z tbl jako (SELECT ROW_NUMBER() nad (zlecenia przez (wybierz 1)) jako rowIndex, * z tabeli) wybierz najlepsze 10 * od tbl gdzie RowIndex> = 10

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

będzie drukować od 15 do 25, a jak limitu w MySQL

+2

Co zrobić, jeśli użytkownik usunął rekord pomiędzy 15 a 25? –

1

Tylko dla rozwiązania rekordu, który działa na większości silników baz danych, choć może nie być najbardziej skuteczny:

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

Pelase uwaga: ostatnia strona nadal zawierałaby wiersze ReturnCount bez względu na to, jaki jest SkipCount. Ale w wielu przypadkach może to być dobre.

1

Równowartość granica jest ustalona ROWCOUNT, ale jeśli chcesz rodzajowe paginacji lepiej napisać kwerendę tak:

;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