Stránkování se často používá v aplikacích, kde uživatel může kliknout na Předchozí /Další můžete procházet stránkami, které tvoří výsledky, nebo kliknutím na číslo stránky přejít přímo na konkrétní stránku.
Při spouštění dotazů na serveru SQL Server můžete stránkovat výsledky pomocí OFFSET
a FETCH
argumenty ORDER BY
doložka. Tyto argumenty byly zavedeny v SQL Server 2012, proto můžete tuto techniku použít, pokud máte SQL Server 2012 nebo vyšší.
V tomto kontextu je stránkování místo, kde rozdělíte výsledky dotazu na menší části, přičemž každá část pokračuje tam, kde skončila předchozí. Pokud například dotaz vrátí 1000 řádků, můžete je stránkovat tak, aby byly vráceny ve skupinách po 100. Aplikace může SQL Serveru předat číslo stránky a velikost stránky a SQL Server ji pak může použít k vrácení pouze data pro požadovanou stránku.
Příklad 1 – Bez stránkování
Nejprve spusťte dotaz, který vrátí všechny řádky v tabulce:
SELECT * FROM Genres ORDER BY GenreId;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | | 7 | Rap | | 8 | Punk | +-----------+---------+
Tento příklad nepoužívá stránkování – zobrazí se všechny výsledky.
Tato sada výsledků je tak malá, že by normálně nevyžadovala stránkování, ale pro účely tohoto článku ji pojďme stránkovat.
Příklad 2 – Zobrazení prvních 3 výsledků
Tento příklad zobrazuje první tři výsledky:
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
V tomto případě specifikuji, že výsledky by měly začínat prvním výsledkem a zobrazovat další tři řádky. To se provádí pomocí následujícího:
OFFSET 0 ROWS
určuje, že by neměl být žádný posun (nulový posun).FETCH NEXT 3 ROWS ONLY
získá další tři řádky od offsetu. Protože jsem zadal offset nula, načtou se první tři řádky.
Pokud bychom chtěli pouze 3 nejlepší výsledky, mohli bychom dosáhnout stejného výsledku pomocí TOP
klauzule místo určení hodnot posunu a načtení. To by nám však neumožnilo udělat další část.
Příklad 3 – Zobrazení dalších 3 výsledků
Nyní si ukážeme následující tři výsledky:
SELECT * FROM Genres ORDER BY GenreId OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Takže jediná věc, kterou jsem změnil, byl offset.
Hodnoty offsetu a načítání mohou být také výrazy poskytnuté jako poddotaz proměnné, parametru nebo konstantního skalárního dotazu. Když je použit poddotaz, nemůže odkazovat na žádné sloupce definované ve vnějším rozsahu dotazu (nelze jej korelovat s vnějším dotazem).
Následující příklady používají výrazy, které ukazují dva přístupy k stránkování výsledků.
Příklad 4 – Stránkování podle čísla řádku
Tento příklad používá výrazy k určení řádku číslo pro začátek.
DECLARE @StartRow int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Zde používám @StartRow int = 1
určit, že výsledky by měly začínat na prvním řádku.
Zde je to, co se stane, když tuto hodnotu zvýším na 2
.
DECLARE @StartRow int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 2 | Jazz | | 3 | Country | | 4 | Pop | +-----------+---------+
Začíná ve druhé řadě. Pomocí této metody mohu určit přesný řádek, na kterém má začít.
Příklad 5 – Stránkování podle čísla stránky
Tento příklad je téměř totožný s předchozím příkladem, kromě toho, že umožňuje zadat číslo stránky, nikoli číslo řádku.
DECLARE @PageNumber int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Takže první výsledek je stejný. Podívejme se však, co se stane, když zvýšíme @PageNumber
až 2
(Tuto proměnnou jsem přejmenoval, aby odrážela její nový účel).
DECLARE @PageNumber int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Tentokrát výsledky začínají na čtvrté řadě. Takže pomocí této metody můžete jednoduše předat číslo stránky místo čísla řádku.
Příklad 6 – Smyčka stránkování
Na závěr uvádíme rychlý příklad, který prochází všechny stránky a udává číslo počátečního řádku pro každou iteraci:
DECLARE @StartRow int = 1, @RowsPerPage int = 3; WHILE (SELECT COUNT(*) FROM Genres) >= @StartRow BEGIN SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY; SET @StartRow = @StartRow + @RowsPerPage; CONTINUE END;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+ (3 rows affected) +-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+ (3 rows affected) +-----------+---------+ | GenreId | Genre | |-----------+---------| | 7 | Rap | | 8 | Punk | +-----------+---------+ (2 rows affected)
Příklad 7 – ROW vs. ROWS
Pokud narazíte na kód, který používá ROW
místo ROWS
, oba argumenty dělají totéž. Jsou to synonyma a jsou poskytovány pro kompatibilitu s ANSI.
Zde je první příklad na této stránce, ale s ROW
místo ROWS
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH NEXT 3 ROW ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Příklad 8 – PRVNÍ vs. DALŠÍ
Totéž platí pro FIRST
a NEXT
. Toto jsou synonyma poskytovaná pro kompatibilitu ANSI.
Zde je předchozí příklad, ale s FIRST
místo NEXT
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH FIRST 3 ROW ONLY;
Výsledek:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+