Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Пагинация в SQL Server с помощта на OFFSET/FETCH

Пагинацията често се използва в приложения, където потребителят може да щракне върху Назад /Следващ за да навигирате в страниците, които съставляват резултатите, или щракнете върху номер на страница, за да отидете директно на конкретна страница.

Когато изпълнявате заявки в SQL Server, можете да подредите резултатите на страници, като използвате OFFSET и FETCH аргументи на ORDER BY клауза. Тези аргументи бяха въведени в SQL Server 2012, следователно можете да използвате тази техника, ако имате SQL Server 2012 или по-нова версия.

В този контекст, разделянето на страници е мястото, където разделяте резултатите от заявката на по-малки парчета, като всяка част продължава там, където предишната завърши. Например, ако заявка върне 1000 реда, можете да ги разбиете на страници, така че да бъдат върнати в групи от 100. Едно приложение може да предаде номера на страницата и размера на страницата на SQL Server и SQL Server може след това да го използва, за да върне само данни за заявената страница.

Пример 1 – Без пагинация

Първо, нека изпълним заявка, която връща всички редове в таблица:

SELECT *
FROM Genres
ORDER BY GenreId;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
| 7         | Rap     |
| 8         | Punk    |
+-----------+---------+

Този пример не използва пагинация – всички резултати се показват.

Този набор от резултати е толкова малък, че обикновено не изисква пагинация, но за целите на тази статия, нека да го разделим на страници.

Пример 2 – Показване на първите 3 резултата

Този пример показва първите три резултата:

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROWS
  FETCH NEXT 3 ROWS ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

В този случай уточнявам, че резултатите трябва да започват от първия резултат и да показват следващите три реда. Това се прави с помощта на следното:

  • OFFSET 0 ROWS указва, че не трябва да има отместване (отместване на нула).
  • FETCH NEXT 3 ROWS ONLY получава следващите три реда от отместването. Тъй като посочих отместване от нула, първите три реда се извличат.

Ако всичко, което искахме, бяха първите 3 резултата, бихме могли да постигнем същия резултат, като използваме TOP клауза вместо посочване на стойностите за отместване и извличане. Това обаче не би ни позволило да направим следващата част.

Пример 3 – Показване на следващите 3 резултата

Сега нека покажем следващите три резултата:

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 3 ROWS
  FETCH NEXT 3 ROWS ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
+-----------+---------+

Така че единственото нещо, което промених, беше изместването.

Стойностите за отместване и извличане могат също да бъдат израз, предоставен като променлива, параметър или константна скаларна подзаявка. Когато се използва подзаявка, тя не може да препраща към колони, дефинирани във външния обхват на заявката (не може да бъде свързан с външната заявка).

Следващите примери използват изрази, за да покажат два подхода за страниране на резултатите.

Пример 4 – Страниране по номер на ред

Този пример използва изрази за определяне на реда номер, от който да започнете.

DECLARE 
  @StartRow int = 1,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET @StartRow - 1 ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Тук използвам @StartRow int = 1 за да посочите, че резултатите трябва да започват от първия ред.

Ето какво се случва, ако увелича тази стойност до 2 .

DECLARE 
  @StartRow int = 2,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET @StartRow - 1 ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 2         | Jazz    |
| 3         | Country |
| 4         | Pop     |
+-----------+---------+

Започва от втория ред. Използвайки този метод, мога да посоча точния ред, от който да започна.

Пример 5 – Страниране по номер на страница

Този пример е почти идентичен с предишния пример, с изключение на това, че ви позволява да посочите номера на страницата, за разлика от номера на реда.

DECLARE 
  @PageNumber int = 1,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Така че първият резултат е същият. Нека обаче да видим какво се случва, когато увеличим @PageNumber до 2 (Преименувах тази променлива, за да отразява новата й цел).

DECLARE 
  @PageNumber int = 2,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
+-----------+---------+

Този път резултатите започват от четвъртия ред. Така че, използвайки този метод, можете просто да предадете номера на страницата, а не номера на реда.

Пример 6 – Цикъл на пагинация

За да завършите, ето един бърз пример, който преглежда всички страници и определя номера на началния ред за всяка итерация:

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;

Резултат:

+-----------+---------+
| 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)

Пример 7 – РЕД срещу РЕДОВЕ

Ако срещнете код, който използва ROW вместо ROWS , и двата аргумента правят едно и също нещо. Те са синоними и са предоставени за съвместимост с ANSI.

Ето първия пример на тази страница, но с ROW вместо ROWS .

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROW
  FETCH NEXT 3 ROW ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Пример 8 – ПЪРВИ срещу СЛЕДВАЩ

Същото важи и за FIRST и NEXT . Това са синоними, предоставени за съвместимост с ANSI.

Ето предишния пример, но с FIRST вместо NEXT .

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROW
  FETCH FIRST 3 ROW ONLY;

Резултат:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Тригери за влизане в SQL Server

  2. SQL Server, Как да задам автоматично увеличение след създаване на таблица без загуба на данни?

  3. Реални срещу плаваща запетая срещу пари

  4. Моля, помогнете за подобряване на статистиката на SQL Server!

  5. Разрешението EXECUTE беше отказано на обекта 'xxxxxxx', база данни 'zzzzzzz', схема 'dbo'