Jak zaimplementować LIMIT z SQL Server?

Odpowiedzi:

131

Uruchamiając SQL SERVER 2005, możesz to zrobić ...

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;

lub coś takiego dla wersji 2000 i starszych ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC
Leon Tayson
źródło
6
Drugie zapytanie kończy się niepowodzeniem, jeśli masz np. 14 wierszy w tabeli. Daje wiersze od 5 do 14, ale potrzebujesz wierszy od 11 do 14. Generalnie kończy się niepowodzeniem w przypadku ostatniej „strony” wyniku, chyba że łączna liczba wierszy jest wielokrotnością rozmiaru „strony”.
Bill Karwin,
151
Stwardnienie rozsiane musi jeszcze raz utrudnić taką prostą rzecz!
Martin,
Oto, co zadziałało w przypadku mnie w SQL Server Management Studio 2017: SELECT * FROM [dbo]. <Insert tableName here> WHERE @@ ROWCOUNT BETWEEN <wstaw min tutaj> i <wstaw maks tutaj>
Artorias2718
Po prostu fantastyczne, działa jak urok w MS SQL Server 2017 select Statement
PatsonLeaner
58

Niezdarny, ale zadziała.

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

Pominięcie klauzuli LIMIT przez MSSQL jest karalne, IMO. Nie powinieneś robić tego rodzaju niezdarnego obejścia.

ceejayoz
źródło
Czy masz inną sugestię, aby to ominąć?
Bigballs
Robiłem dużo Google, kiedy ostatnio miałem do czynienia z MSSQL i było to najlepsze rozwiązanie, jakie znalazłem. Niezbyt przyjemne, ale działa.
ceejayoz
To rozwiązanie działa tylko wtedy, gdy zestaw wyników zawiera unikatową kolumnę. Naśladowanie LIMIT dla dowolnego zapytania nie jest ogólnym rozwiązaniem.
Bill Karwin
1
Jestem teraz w podobnym dylemacie ... Jednak w moim przypadku jestem wkurzony ... Jeszcze bardziej kryminalne jest, gdy tak zwani `` eksperci '' dba decydują, że unikalny klucz jest niepotrzebny w stole ... DOWOLNY stół ... Nawet nie poruszaj tematu kluczy obcych i ograniczeń!
Andrew Rollings,
Problem z tym jest taki, że nie radzi sobie zbyt dobrze z klauzulami WHERE ... Spróbuję tabel tymczasowych, ponieważ nie działają dla mnie.
paskudny pasty
41

Począwszy od SQL SERVER 2012, możesz użyć klauzuli 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

Może to nie działać poprawnie, jeśli kolejność nie jest unikalna.

Jeśli zapytanie zostanie zmodyfikowane na ORDER BY OrderDate, zwrócony zestaw wyników nie jest zgodny z oczekiwaniami.

user4047259
źródło
Użycie opcji „with” zajmuje tylko połowę czasu na zakończenie zapytania - zobacz odpowiedź @Leon Tayson. Nie mam pojęcia, co zrobił Microsoft, żeby to spowolnić.
Human
1
Dlaczego nie jest to akceptowana odpowiedź? Jesteśmy w 2018 roku na głośny płacz!
Skipper
1
@Skipper right. zaakceptowany nadal działa. Po prostu zagłosujmy na ten, aby odzwierciedlić aktualizację.
korona
18

To jest prawie duplikat pytania, które zadałem w październiku: Emuluj klauzulę MySQL LIMIT w Microsoft SQL Server 2000

Jeśli używasz Microsoft SQL Server 2000, nie ma dobrego rozwiązania. Większość ludzi musi uciekać się do przechwytywania wyniku zapytania w tymczasowej tabeli z IDENTITYkluczem podstawowym. Następnie wykonaj zapytanie dotyczące kolumny klucza podstawowego, używając BETWEENwarunku.

Jeśli używasz programu Microsoft SQL Server 2005 lub nowszego, masz ROW_NUMBER()funkcję, dzięki której możesz uzyskać ten sam wynik, ale unikaj tabeli tymczasowej.

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;

Można również napisać to jako wspólnego wyrażenia tabeli , jak pokazano na @Leon Tayson za odpowiedź .

Bill Karwin
źródło
ROW_NUMBER () OVER (ORDER BY) otrzymuje punkty za bycie poprawnym w ANSI SQL: 2003, chociaż obsługa DBMS innych niż SQL Server jest bardzo nierówna. I jest to oczywiście dość niezgrabne ...
bobince
@bobince: Okazuje się, że Oracle, Microsoft SQL Server 2005, IBM DB2 i PostgreSQL 8.4 obsługują wszystkie funkcje okna. To obejmuje ogromną większość rynku SQL. Wsparcie jest nieregularne tylko wtedy, gdy używasz MySQL, SQLite lub starej wersji DB powyżej.
Bill Karwin,
17

Oto jak ograniczam wyniki w MS SQL Server 2012:

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

UWAGA: OFFSETmoże być używany tylko z lub w tandemie ORDER BY.

Aby wyjaśnić linię kodu OFFSET xx ROWS FETCH NEXT yy ROW ONLY

Jest xxto numer rekordu / wiersza, z którego chcesz rozpocząć pobieranie w tabeli, tj .: Jeśli w tabeli 1 jest 40 rekordów, powyższy kod zacznie pobierać z wiersza 10.

To yyliczba rekordów / wierszy, które chcesz pobrać z tabeli.

Aby oprzeć się na poprzednim przykładzie: Jeśli tabela 1 ma 40 rekordów i zacząłeś wyciągać z wiersza 10 i chwyć NEXT zestaw 10 ( yy). Oznaczałoby to, że powyższy kod pobierze rekordy z tabeli 1, zaczynając od wiersza 10, a kończąc na 20. Tym samym wyciągając wiersze 10–20.

Sprawdź link, aby uzyskać więcej informacji na temat OFFSET

Jeremy
źródło
Zgadzam się na to. W moim przypadku muszę użyć tego warunku dla mojego niestandardowego zapytania natywnego, dlatego klauzule vanilla findBy w JPA nie pomogły zbytnio. Ta opcja działała zgodnie z oczekiwaniami. Proszę
potraktować
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
źródło
Cóż, właśnie sprawdziłem, SQL Server okazał się wystarczająco inteligentny, aby zatrzymać się na warunkach ROW_NUMBER (), jeśli w klauzuli ORDER BY znajduje się indeksowana kolumna.
Quassnoi
9

Składniowo zapytanie MySQL LIMIT wygląda mniej więcej tak:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

Można to przetłumaczyć na Microsoft SQL Server, na przykład

SELECT * FROM 
(
    SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table
) a
WHERE rnum > OFFSET

Teraz twoje zapytanie select * from table1 LIMIT 10,20będzie wyglądało tak:

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

źródło
2

To jeden z powodów, dla których staram się unikać korzystania z MS Server ... ale w każdym razie. Czasami po prostu nie masz opcji (yei! I muszę użyć przestarzałej wersji !!).

Moja sugestia to utworzenie wirtualnego stołu:

Z:

SELECT * FROM table

Do:

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

Następnie po prostu zapytaj:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

Jeśli pola są dodawane lub usuwane, „wiersz” jest aktualizowany automatycznie.

Głównym problemem związanym z tą opcją jest naprawiona funkcja ORDER BY. Więc jeśli chcesz mieć inną kolejność, musisz utworzyć inny widok.

AKTUALIZACJA

Jest inny problem z tym podejściem: jeśli spróbujesz filtrować dane, nie zadziała zgodnie z oczekiwaniami. Na przykład, jeśli:

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

WHERE ogranicza się do tych danych, które znajdują się w wierszach od 10 do 20 (zamiast przeszukiwać cały zbiór danych i ograniczać dane wyjściowe).

lepe
źródło
1

Jest to wieloetapowe podejście, które będzie działać w 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
wieża
źródło
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
źródło
To było dla mnie świetne rozwiązanie.
Tyde
1

Musisz spróbować. W poniższym zapytaniu możesz zobaczyć grupowanie według, sortowanie według, pomijanie wierszy i ograniczanie wierszy.

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 duński
źródło
0
SELECT TOP 10 * FROM table;

Jest taki sam jak

SELECT * FROM table LIMIT 0,10;

Oto artykuł o implementacji Limit w MsSQL. Miło się go przeczytać, szczególnie komentarze.

Ólafur Waage
źródło
1
Dzięki, ale chcę rekord między 10 a 20, jest sposób, aby to zrobić?
Bigballs
5
Ta odpowiedź nie odpowiada na pytanie o pochodzenie, ale jest przydatna, jeśli ktoś taki jak ja musi wiedzieć, jak uzyskać pierwsze N ​​wyników i dostać się tutaj przez Google itp ...
brianlmerritt
0

W SQL nie istnieje słowo kluczowe LIMIT. Jeśli potrzebujesz tylko ograniczonej liczby wierszy, powinieneś użyć słowa kluczowego TOP, które jest podobne do LIMIT.

Mitul Panchal
źródło
0

Jeśli Twój identyfikator jest unikalnym typem identyfikatora lub Twój identyfikator w tabeli nie jest posortowany, wykonaj poniższe czynności.

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



Kod będzie

wybierz * z limitu 2,5
user3244012
źródło
0

lepiej użyj tego w MSSQLExpress 2017.

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;

- Nadanie kolumny [Liczba] i przypisanie każdemu wierszowi unikalnego liczenia bez zamawiania czegoś, a następnie ponownie wybierz ponownie, gdzie możesz określić swoje limity .. :)

user1308314
źródło
0

Jeden z możliwych sposobów uzyskania wyniku, jak poniżej, mam nadzieję, że to pomoże.

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
źródło
0

Łatwy sposób

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 jest obowiązkowe

Turendu
źródło
-2

Jeśli dobrze pamiętam (minęło trochę czasu, odkąd korzystałem z SQL Server), możesz użyć czegoś takiego: (2005 i nowsze)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20
Kris
źródło
SQL Server 2012: Msg 207, poziom 16, stan 1, wiersz 5 Nieprawidłowa nazwa kolumny „RowNum”.
e-info128
brzmi tak, jakbyś miał gdzieś literówkę w swoim oświadczeniu. RowNum to nazwa, którą przypisujemy do wyrażenia. Opublikuj swój problem ze źródłem, a społeczność ci pomoże
Kris
To jest nieprawidłowa składnia. Nie możesz odwoływać się WHEREdo aliasu zdefiniowanego w SELECTklauzuli tego samego poziomu .
ypercubeᵀᴹ