Czy istnieje sposób w SQL Server, aby uzyskać wyniki zaczynając od podanego przesunięcia? Na przykład w innym typie bazy danych SQL można:
SELECT * FROM MyTable OFFSET 50 LIMIT 25
aby uzyskać wyniki 51-75. Wydaje się, że ta konstrukcja nie istnieje w programie SQL Server.
Jak mogę to zrobić bez ładowania wszystkich wierszy, na których mi nie zależy? Dzięki!
sql
sql-server
Alex
źródło
źródło
Odpowiedzi:
Unikałbym używania
SELECT *
. Określ kolumny, które faktycznie chcesz, nawet jeśli mogą to być wszystkie.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
Efektywne stronicowanie dużych zestawów wyników w SQL Server 2000
Bardziej wydajna metoda przeglądania dużych zestawów wyników
źródło
SELECT *
oznacza to, że jeśli struktura tabeli ulegnie zmianie, zapytanie nadal działa, ale daje inne wyniki. Jeśli dodana jest kolumna, może się to przydać (chociaż nadal musisz gdzieś używać jej nazwy); jeśli kolumna zostanie usunięta lub zmieniona zostanie jej nazwa, lepiej, aby kod SQL ulegał awarii w widoczny sposób, niż kod zachowywał się dziwnie, ponieważ zmienna nie została zainicjowana.Jeśli będziesz przetwarzać wszystkie strony w kolejności, po prostu zapamiętaj ostatnią wartość klucza widoczną na poprzedniej stronie i użycie
TOP (25) ... WHERE Key > @last_key ORDER BY Key
może być najlepszą metodą, jeśli istnieją odpowiednie indeksy, aby umożliwić wydajne wyszukiwanie - lub kursor API, jeśli nie są .Aby wybrać dowolną stronę, najlepszym rozwiązaniem dla SQL Server 2005-2008 R2 jest prawdopodobnie
ROW_NUMBER
iBETWEEN
W przypadku SQL Server 2012+ możesz w tym celu użyć rozszerzonej klauzuli ORDER BY .
SELECT * FROM MyTable ORDER BY OrderingColumn ASC OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY
Chociaż dopiero się okaże, jak dobrze będzie działać ta opcja .
źródło
To jest w jedną stronę (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
a 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
źródło
Możesz użyć
ROW_NUMBER()
funkcji, aby uzyskać to, czego chcesz:SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t WHERE RowNr BETWEEN 10 AND 20
źródło
Jest
OFFSET .. FETCH
w SQL Server 2012, ale musisz określićORDER BY
kolumnę.Jeśli naprawdę nie masz żadnej jawnej kolumny, którą mógłbyś przekazać jako
ORDER BY
kolumnę (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ą wyraźnie zamówienia. Spowoduje to wygenerowanie całkiem przypadkowej kolejności bez dodatkowych kosztów.
źródło
W przypadku tabel z większą liczbą 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 ze wszystkimi kolumnami zwracane są tylko pasujące wiersze.
źródło
Zobacz mój wybór dla 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ę;)
źródło
SELECT TOP 75 * FROM MyTable EXCEPT SELECT TOP 50 * FROM MyTable
źródło
W zależności od wersji nie możesz tego zrobić bezpośrednio, ale możesz zrobić coś hackerskiego
select top 25 * from ( select top 75 * from table order by field asc ) a order by field desc
gdzie „pole” jest kluczem.
źródło
Poniżej zostanie wyświetlonych 25 rekordów, z wyłączeniem pierwszych 50 rekordów w programie 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
źródło
Należy zachować ostrożność podczas używania tego
ROW_NUMBER() OVER (ORDER BY)
stwierdzenia, ponieważ wydajność jest dość niska. To samo dotyczy używania wyrażeń wspólnych tabel zROW_NUMBER()
tym jest jeszcze gorzej. Używam następującego fragmentu kodu, który okazał się nieco szybszy niż użycie zmiennej tabeli z tożsamością w celu podania numeru 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
źródło
Używam tej techniki do paginacji. Nie pobieram wszystkich wierszy. Na przykład, jeśli moja strona musi wyświetlić 100 pierwszych wierszy, pobieram tylko 100 z klauzulą where. Wynik SQL powinien mieć unikalny klucz.
Tabela zawiera następujące elementy:
Ta sama ranga zostanie przypisana do więcej niż jednego KeyId.
SQL jest
select top 2 * from Table1 where Rank >= @Rank and ID > @Id
Po raz pierwszy zdaję 0 dla obu. Drugi przejazd 1 i 14. Trzeci przejazd 2 i 6 ....
Wartość dziesiątego rekordu Rank & Id jest przekazywana do następnego
Będzie to miało najmniejszy nacisk na system
źródło
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)
źródło
@Offset + @Limit - 1
? Jeśli @Limit wynosi 10, zwróci to 11 wierszy.Najlepszym sposobem, aby to zrobić bez marnowania czasu na zamawianie rekordów, jest:
select 0 as tmp,Column1 from Table1 Order by tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY
zajmuje to mniej niż jedną sekundę!
najlepsze rozwiązanie dla dużych stołów.
źródło
Szukałem tej odpowiedzi już od jakiegoś czasu (dla zapytań ogólnych) i znalazłem inny sposób zrobienia tego na SQL Server 2000+ przy użyciu ROWCOUNT i kursorów, bez TOP lub jakiejkolwiek tabeli tymczasowej.
Za pomocą
SET ROWCOUNT [OFFSET+LIMIT]
możesz ograniczyć wyniki, a kursorami przejdź bezpośrednio do żądanego wiersza, a następnie zapętlaj do końca.Twoje zapytanie wyglądałoby więc tak:
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
źródło
W przypadku programu SQL Server 2012 (11.x) i nowszych oraz Azure SQL Database możesz również mieć „fetch_row_count_expression”, a także klauzulę ORDER BY.
USE AdventureWorks2012; GO -- Specifying variables for OFFSET and FETCH values DECLARE @skip int = 0 , @take int = 8; SELECT DepartmentID, Name, GroupName FROM HumanResources.Department ORDER BY DepartmentID ASC OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY;
https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-ver15
Uwaga OFFSET Określa liczbę wierszy do pominięcia, zanim zacznie zwracać wiersze z wyrażenia zapytania. NIE jest to numer wiersza początkowego. Tak więc, aby uwzględnić pierwszy rekord, musi wynosić 0.
źródło