Phân trang thường được sử dụng trong các ứng dụng mà người dùng có thể nhấp vào Trước đó / Tiếp theo để điều hướng các trang tạo nên kết quả hoặc nhấp vào số trang để chuyển thẳng đến một trang cụ thể.
Khi chạy các truy vấn trong SQL Server, bạn có thể phân trang kết quả bằng cách sử dụng OFFSET
và FETCH
các đối số của ORDER BY
mệnh đề. Các đối số này đã được giới thiệu trong SQL Server 2012, do đó bạn có thể sử dụng kỹ thuật này nếu bạn có SQL Server 2012 trở lên.
Trong ngữ cảnh này, phân trang là nơi bạn chia kết quả truy vấn thành các phần nhỏ hơn, mỗi phần tiếp tục ở vị trí kết thúc trước đó. Ví dụ:nếu một truy vấn trả về 1000 hàng, bạn có thể phân trang chúng để chúng được trả về theo nhóm 100. Một ứng dụng có thể chuyển số trang và kích thước trang cho SQL Server và SQL Server sau đó có thể sử dụng nó để trả về dữ liệu cho trang được yêu cầu.
Ví dụ 1 - Không phân trang
Đầu tiên, hãy chạy một truy vấn trả về tất cả các hàng trong một bảng:
SELECT * FROM Genres ORDER BY GenreId;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | | 7 | Rap | | 8 | Punk | +-----------+---------+
Ví dụ này không sử dụng phân trang - tất cả các kết quả đều được hiển thị.
Tập hợp kết quả này quá nhỏ nên thông thường nó sẽ không yêu cầu phân trang, nhưng với mục đích của bài viết này, chúng ta hãy phân trang nó.
Ví dụ 2 - Hiển thị 3 kết quả đầu tiên
Ví dụ này hiển thị ba kết quả đầu tiên:
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Trong trường hợp này, tôi chỉ định rằng kết quả phải bắt đầu từ kết quả đầu tiên và hiển thị ba hàng tiếp theo. Điều này được thực hiện bằng cách sử dụng như sau:
-
OFFSET 0 ROWS
chỉ định rằng không được bù trừ (độ lệch bằng 0). -
FETCH NEXT 3 ROWS ONLY
lấy ba hàng tiếp theo từ phần bù. Vì tôi đã chỉ định độ lệch bằng 0 nên ba hàng đầu tiên sẽ được tìm nạp.
Nếu tất cả những gì chúng tôi muốn là 3 kết quả hàng đầu, chúng tôi có thể đạt được kết quả tương tự bằng cách sử dụng TOP
thay vì chỉ định giá trị bù đắp và tìm nạp. Tuy nhiên, điều này sẽ không cho phép chúng tôi làm phần tiếp theo.
Ví dụ 3 - Hiển thị 3 kết quả tiếp theo
Bây giờ, hãy hiển thị ba kết quả tiếp theo:
SELECT * FROM Genres ORDER BY GenreId OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Vì vậy, điều duy nhất tôi thay đổi là phần bù.
Các giá trị bù đắp và tìm nạp cũng có thể là một biểu thức được cung cấp dưới dạng một biến, tham số hoặc truy vấn con vô hướng hằng số. Khi một truy vấn con được sử dụng, nó không thể tham chiếu đến bất kỳ cột nào được xác định trong phạm vi truy vấn bên ngoài (nó không thể tương quan với truy vấn bên ngoài).
Các ví dụ sau đây sử dụng các biểu thức để chỉ ra hai cách tiếp cận để phân trang kết quả.
Ví dụ 4 - Phân trang theo số hàng
Ví dụ này sử dụng các biểu thức để chỉ định hàng số để bắt đầu tại.
DECLARE @StartRow int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Ở đây, tôi sử dụng @StartRow int = 1
để chỉ định rằng kết quả phải bắt đầu ở hàng đầu tiên.
Đây là những gì sẽ xảy ra nếu tôi tăng giá trị đó lên 2
.
DECLARE @StartRow int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 2 | Jazz | | 3 | Country | | 4 | Pop | +-----------+---------+
Nó bắt đầu ở hàng thứ hai. Sử dụng phương pháp này, tôi có thể chỉ định hàng chính xác để bắt đầu.
Ví dụ 5 - Phân trang theo số trang
Ví dụ này gần giống với ví dụ trước, ngoại trừ việc nó cho phép bạn chỉ định số trang, trái ngược với số hàng.
DECLARE @PageNumber int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Vì vậy, kết quả đầu tiên là như nhau. Tuy nhiên, hãy xem điều gì sẽ xảy ra khi chúng ta tăng @PageNumber
thành 2
(Tôi đã đổi tên biến này để phản ánh mục đích mới của nó).
DECLARE @PageNumber int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Lần này kết quả bắt đầu từ hàng thứ tư. Vì vậy, bằng cách sử dụng phương pháp này, bạn có thể chỉ cần chuyển số trang chứ không phải số hàng.
Ví dụ 6 - Vòng lặp phân trang
Để kết thúc, đây là một ví dụ nhanh lặp lại tất cả các trang và chỉ định số hàng bắt đầu cho mỗi lần lặp:
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;
Kết quả:
+-----------+---------+ | 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)
Ví dụ 7 - ROW so với ROWS
Nếu bạn gặp mã sử dụng ROW
thay vì ROWS
, cả hai đối số đều làm điều tương tự. Chúng là từ đồng nghĩa và được cung cấp để tương thích với ANSI.
Đây là ví dụ đầu tiên trên trang này, nhưng với ROW
thay vì ROWS
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH NEXT 3 ROW ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Ví dụ 8 - FIRST so với NEXT
Điều tương tự cũng áp dụng cho FIRST
và NEXT
. Đây là những từ đồng nghĩa được cung cấp cho khả năng tương thích ANSI.
Đây là ví dụ trước nhưng với FIRST
thay vì NEXT
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH FIRST 3 ROW ONLY;
Kết quả:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+