Przesunięcie wiersza w SQL Server

Czy Jest jakiś sposób w SQL Server, aby uzyskać wyniki zaczynające się od danego offsetu? Na przykład w innym typie bazy danych SQL można wykonać:

SELECT * FROM MyTable OFFSET 50 LIMIT 25

Aby uzyskać wyniki 51-75. Ta konstrukcja nie wydaje się istnieć w SQL Server.

Jak mogę to osiągnąć bez ładowania wszystkich wierszy, na których mi nie zależy? Dzięki!

Author: ManoDestra, 2008-10-09

15 answers

Unikałbym używania SELECT *. Określ kolumny, które chcesz, nawet jeśli mogą to być wszystkie z nich.

SQL Server 2005+

SELECT col1, col2 
FROM (
    SELECT col1, col2, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
    FROM MyTable
) AS MyDerivedTable
WHERE MyDerivedTable.RowNum BETWEEN @startRow AND @endRow

SQL Server 2000

Wydajne przeglądanie dużych zestawów wyników w SQL Server 2000

Bardziej efektywna metoda stronicowania dużych zbiorów wyników

 148
Author: Brian Kim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-28 04:45:49

Jeśli będziesz przetwarzać wszystkie strony w kolejności, to po prostu zapamiętaj ostatnią wartość klucza widoczną na poprzedniej stronie i użyj TOP (25) ... WHERE Key > @last_key ORDER BY Key może być najlepiej działającą metodą, jeśli istnieją odpowiednie indeksy, które pozwalają na efektywne wyświetlanie tej strony - lub kursor API , Jeśli nie.

Do wyboru strony arbiter najlepszym rozwiązaniem dla SQL Server 2005-2008 R2 jest prawdopodobnie ROW_NUMBER i BETWEEN

Dla SQL Server 2012+ możesz użyć rozszerzonej klauzuli ORDER BY do tego potrzeba.

SELECT  *
FROM     MyTable 
ORDER BY OrderingColumn ASC 
OFFSET  50 ROWS 
FETCH NEXT 25 ROWS ONLY 

Chociaż okaże się, jak dobrze sprawdzi się ta opcja .

 91
Author: Martin Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 12:42:40

This is one way (SQL2000)

SELECT * FROM
(
    SELECT TOP (@pageSize) * FROM
    (
        SELECT TOP (@pageNumber * @pageSize) *
        FROM tableName 
        ORDER BY columnName ASC
    ) AS t1 
    ORDER BY columnName DESC
) AS t2 
ORDER BY columnName ASC

I to jest inny sposób (SQL 2005)

;WITH results AS (
    SELECT 
        rowNo = ROW_NUMBER() OVER( ORDER BY columnName ASC )
        , *
    FROM tableName 
) 
SELECT * 
FROM results
WHERE rowNo between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize
 22
Author: leoinfo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 03:43:47

Możesz użyć funkcji ROW_NUMBER(), Aby uzyskać to, co chcesz:

SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t
WHERE RowNr BETWEEN 10 AND 20
 10
Author: Matthias Meid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-24 07:07:38

Dla tabel z większą ilością i dużymi kolumnami danych preferuję:

SELECT 
  tablename.col1,
  tablename.col2,
  tablename.col3,
  ...
FROM
(
  (
    SELECT
      col1
    FROM 
    (
      SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum
      FROM tablename
      WHERE ([CONDITION])
    )
    AS T1 WHERE T1.RowNum BETWEEN [OFFSET] AND [OFFSET + LIMIT]
  )
  AS T2 INNER JOIN tablename ON T2.col1=tablename.col1
);

-

[CONDITION] can contain any WHERE clause for searching.
[OFFSET] specifies the start,
[LIMIT] the maximum results.

Ma znacznie lepszą wydajność w tabelach z dużymi danymi, takimi jak Blob, ponieważ funkcja ROW_NUMBER musi przeglądać tylko jedną kolumnę, a tylko pasujące wiersze są zwracane ze wszystkimi kolumnami.

 6
Author: Arthur van Dijk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-25 15:37:59

W SQL Server 2012 jest OFFSET .. FETCH, ale musisz podać kolumnę ORDER BY.

Jeśli naprawdę nie masz żadnej wyraźnej kolumny, którą mógłbyś przekazać jako ORDER BY kolumna (jak sugerowali inni), możesz użyć tej sztuczki:

SELECT * FROM MyTable 
ORDER BY @@VERSION 
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

... lub

SELECT * FROM MyTable 
ORDER BY (SELECT 0)
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

Używamy go w jOOQ, gdy użytkownicy nie określają wprost kolejności. Spowoduje to wtedy dość losowe zamawianie bez żadnych dodatkowych kosztów.

 6
Author: Lukas Eder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-13 06:39:01

Zobacz mój wybór paginatora

SELECT TOP @limit * FROM (
   SELECT ROW_NUMBER() OVER (ORDER BY colunx ASC) offset, * FROM (

     -- YOU SELECT HERE
     SELECT * FROM mytable


   ) myquery
) paginator
WHERE offset > @offset

To rozwiązuje paginację;)

 5
Author: PerfectLion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-23 18:34:44
SELECT TOP 75 * FROM MyTable
EXCEPT 
SELECT TOP 50 * FROM MyTable
 3
Author: Jithin Shaji,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-21 08:05:32

W zależności od wersji nie można tego zrobić bezpośrednio, ale można zrobić coś hacky jak

select top 25 *
from ( 
  select top 75 *
  from   table 
  order by field asc
) a 
order by field desc 

Gdzie' pole ' jest kluczem.

 2
Author: Unsliced,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-09 16:20:56

Powinieneś być ostrożny, gdy używasz instrukcji row_number () OVER (ORDER BY), ponieważ performane jest dość słabe. To samo dotyczy używania zwykłych wyrażeń tabel z funkcją row_number (), co jest jeszcze gorsze. Używam poniższego fragmentu, który okazał się nieco szybszy niż użycie zmiennej tabelkowej z tożsamością, aby podać numer strony.

DECLARE @Offset INT = 120000
DECLARE @Limit INT = 10

DECLARE @ROWCOUNT INT = @Offset+@Limit
SET ROWCOUNT @ROWCOUNT

SELECT * FROM MyTable INTO #ResultSet
WHERE MyTable.Type = 1

SELECT * FROM
(
    SELECT *, ROW_NUMBER() OVER(ORDER BY SortConst ASC) As RowNumber FROM
    (
        SELECT *, 1 As SortConst FROM #ResultSet
    ) AS ResultSet
) AS Page
WHERE RowNumber BETWEEN @Offset AND @ROWCOUNT

DROP TABLE #ResultSet
 2
Author: Patrik Melander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-27 15:10:37

Po wyświetli 25 rekordów z wyłączeniem pierwszych 50 rekordów działających w SQL Server 2012.

SELECT * FROM MyTable ORDER BY ID OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY;

Możesz zastąpić ID jako swoje Wymaganie

 2
Author: Shb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-09 09:56:23

Używam tej techniki do paginacji. Nie zbieram wszystkich rzędów. Na przykład, jeśli moja strona musi wyświetlić górne wiersze 100, pobieram tylko 100 z klauzulą where. Wyjście SQL powinno mieć unikalny klucz.

Tabela zawiera:

ID, KeyId, Rank

Ta sama ranga będzie przypisana dla więcej niż jednego KeyId.

SQL to select top 2 * from Table1 where Rank >= @Rank and ID > @Id

Po raz pierwszy zdaję 0 za oba. Drugi raz pass 1 i 14. 3. time pass 2 i 6....

Wartość dziesiątego ranga & ID rekordu jest przekazywane do następnego

11  21  1
14  22  1
7   11  1
6   19  2
12  31  2
13  18  2

To będzie miało najmniejszy nacisk na system

 1
Author: Ravi Ramaswamy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-18 21:34:48

W SqlServer2005 możesz wykonać następujące czynności:

DECLARE @Limit INT
DECLARE @Offset INT
SET @Offset = 120000
SET @Limit = 10

SELECT 
    * 
FROM
(
   SELECT 
       row_number() 
   OVER 
      (ORDER BY column) AS rownum, column2, column3, .... columnX
   FROM   
     table
) AS A
WHERE 
 A.rownum BETWEEN (@Offset) AND (@Offset + @Limit-1) 
 1
Author: Aheho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-27 18:09:50

Szukałem tej odpowiedzi od jakiegoś czasu (dla ogólnych zapytań) i znalazłem inny sposób na zrobienie tego na SQL Server 2000+ za pomocą ROWCOUNT i kursorów i bez TOP lub żadnej tymczasowej tabeli.

Za pomocą SET ROWCOUNT [OFFSET+LIMIT] możesz ograniczyć wyniki i za pomocą kursorów przejść bezpośrednio do żądanego wiersza, a następnie zapętlić 'do końca.

Więc twoje zapytanie będzie takie:

SET ROWCOUNT 75 -- (50 + 25)
DECLARE MyCursor SCROLL CURSOR FOR SELECT * FROM pessoas
OPEN MyCursor
FETCH ABSOLUTE 50 FROM MyCursor -- OFFSET
WHILE @@FETCH_STATUS = 0 BEGIN
    FETCH next FROM MyCursor
END
CLOSE MyCursor
DEALLOCATE MyCursor
SET ROWCOUNT 0
 0
Author: Capilé,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-13 17:58:02

Najlepszy sposób, aby to zrobić bez marnowania czasu na zamawianie płyt jest taki:

select 0 as tmp,Column1 from Table1 Order by tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY
To zajmuje mniej niż sekundę!
najlepsze rozwiązanie dla dużych stołów.
 0
Author: Pishgaman.org,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-15 13:53:13