Cách tốt nhất (hiệu suất khôn ngoan) để phân trang kết quả trong SQL Server 2000, 2005, 2008, 2012 nếu bạn cũng muốn có được tổng số kết quả (trước khi phân trang)?
Cách tốt nhất (hiệu suất khôn ngoan) để phân trang kết quả trong SQL Server 2000, 2005, 2008, 2012 nếu bạn cũng muốn có được tổng số kết quả (trước khi phân trang)?
Câu trả lời:
Lấy tổng số kết quả và phân trang là hai thao tác khác nhau. Vì lợi ích của ví dụ này, hãy giả sử rằng truy vấn bạn đang xử lý là
SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
Trong trường hợp này, bạn sẽ xác định tổng số kết quả bằng cách sử dụng:
SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'
... có vẻ không hiệu quả, nhưng thực sự khá hiệu quả, giả sử tất cả các chỉ mục, vv được thiết lập đúng.
Tiếp theo, để lấy lại kết quả thực tế theo kiểu phân trang, truy vấn sau đây sẽ hiệu quả nhất:
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, *
FROM Orders
WHERE OrderDate >= '1980-01-01'
) AS RowConstrainedResult
WHERE RowNum >= 1
AND RowNum < 20
ORDER BY RowNum
Điều này sẽ trả về các hàng 1-19 của truy vấn ban đầu. Điều thú vị ở đây, đặc biệt là đối với các ứng dụng web, là bạn không phải giữ bất kỳ trạng thái nào, ngoại trừ số hàng được trả về.
Cuối cùng, Microsoft SQL Server 2012 đã được phát hành, tôi thực sự thích sự đơn giản của nó cho việc phân trang, bạn không phải sử dụng các truy vấn phức tạp như đã trả lời ở đây.
Để nhận được 10 hàng tiếp theo, chỉ cần chạy truy vấn này:
SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
Những điểm chính cần xem xét khi sử dụng nó:
ORDER BY
là bắt buộc để sử dụng OFFSET ... FETCH
mệnh đề.OFFSET
mệnh đề là bắt buộc với FETCH
. Bạn không thể sử dụng ORDER BY ...
FETCH
.TOP
không thể được kết hợp với OFFSET
và FETCH
trong cùng một biểu thức truy vấn.LISTAGG()
/ GROUP_CONCAT()
.
FOR XML
: stackoverflow.com/a/273330/429949
FOR XML PATH ('')
. Đầu tiên, nó thay thế các ký tự điều khiển XML bằng mã thực thể XML. Hy vọng bạn không có <
, >
hoặc &
trong dữ liệu của bạn! Thứ hai, FOR XML PATH ('')
được sử dụng theo cách này thực sự là cú pháp không có giấy tờ. Bạn phải chỉ định một cột được đặt tên hoặc một tên thành phần thay thế. Làm không phải là không có trong tài liệu, có nghĩa là hành vi là không đáng tin cậy. Thứ ba, chúng ta càng chấp nhận FOR XML PATH ('')
cú pháp bị hỏng , thì càng ít khả năng MS thực sự cung cấp một chức năng thực sự LISTAGG() [ OVER() ]
như họ cần.
Thật đáng kinh ngạc, không có câu trả lời nào khác đề cập đến cách nhanh nhất để phân trang trong tất cả các phiên bản SQL Server. Độ lệch có thể rất chậm đối với số lượng trang lớn như được điểm chuẩn ở đây . Có một cách hoàn toàn khác, nhanh hơn nhiều để thực hiện phân trang trong SQL. Điều này thường được gọi là "phương pháp tìm kiếm" hoặc "phân trang keyset" như được mô tả trong bài đăng trên blog này ở đây .
SELECT TOP 10 first_name, last_name, score, COUNT(*) OVER()
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
Các giá trị @previousScore
và @previousPlayerId
là các giá trị tương ứng của bản ghi cuối cùng từ trang trước. Điều này cho phép bạn tìm nạp trang "tiếp theo". Nếu ORDER BY
hướng là ASC
, chỉ cần sử dụng >
thay thế.
Với phương pháp trên, bạn không thể ngay lập tức chuyển sang trang 4 mà không cần tìm nạp 40 bản ghi trước. Nhưng thông thường, bạn không muốn nhảy xa như vậy. Thay vào đó, bạn nhận được một truy vấn nhanh hơn nhiều có thể có thể tìm nạp dữ liệu trong thời gian liên tục, tùy thuộc vào việc lập chỉ mục của bạn. Ngoài ra, các trang của bạn vẫn "ổn định", bất kể dữ liệu cơ bản có thay đổi hay không (ví dụ trên trang 1, trong khi bạn ở trang 4).
Đây là cách tốt nhất để thực hiện phân trang khi lười tải nhiều dữ liệu hơn trong các ứng dụng web.
Lưu ý, "phương pháp tìm kiếm" còn được gọi là phân trang keyset .
Các COUNT(*) OVER()
chức năng cửa sổ sẽ giúp bạn đếm số lượng tổng số hồ sơ "trước khi pagination". Nếu bạn đang sử dụng SQL Server 2000, bạn sẽ phải sử dụng hai truy vấn cho COUNT(*)
.
OFFSET .. FETCH
hay với các ROW_NUMBER()
thủ thuật trước đó .
RowNumber
cung cấp cho tôi 10 mục nhất quán trên mỗi trang. [3] nó không hoạt động với các lưới hiện có giả định pagenumber
và pagesize
.
Từ SQL Server 2012, chúng tôi có thể sử dụng OFFSET
và FETCH NEXT
khoản để đạt được phân trang.
Hãy thử điều này, đối với SQL Server:
Trong SQL Server 2012, một tính năng mới đã được thêm vào trong mệnh đề ORDER BY, để truy vấn tối ưu hóa dữ liệu đã đặt, giúp công việc phân trang dữ liệu dễ dàng hơn cho bất kỳ ai viết bằng T-SQL cũng như cho toàn bộ Kế hoạch thực thi trong SQL Server.
Bên dưới tập lệnh T-SQL có cùng logic được sử dụng trong ví dụ trước.
--CREATING A PAGING WITH OFFSET and FETCH clauses IN "SQL SERVER 2012" DECLARE @PageNumber AS INT, @RowspPage AS INT SET @PageNumber = 2 SET @RowspPage = 10 SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE FROM TB_EXAMPLE ORDER BY ID_EXAMPLE OFFSET ((@PageNumber - 1) * @RowspPage) ROWS FETCH NEXT @RowspPage ROWS ONLY;
MSDN: ROW_NUMBER (Giao dịch-SQL)
Trả về số thứ tự của một hàng trong một phân vùng của tập kết quả, bắt đầu từ 1 cho hàng đầu tiên trong mỗi phân vùng.
Ví dụ sau đây trả về các hàng có các số từ 50 đến 60 được bao gồm theo thứ tự của OrderDate.
WITH OrderedOrders AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY FirstName DESC) AS RowNumber,
FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
FROM [dbo].[vSalesPerson]
)
SELECT RowNumber,
FirstName, LastName, Sales YTD
FROM OrderedOrders
WHERE RowNumber > 50 AND RowNumber < 60;
RowNumber FirstName LastName SalesYTD
--- ----------- ---------------------- -----------------
1 Linda Mitchell 4251368.54
2 Jae Pak 4116871.22
3 Michael Blythe 3763178.17
4 Jillian Carson 3189418.36
5 Ranjit Varkey Chudukatil 3121616.32
6 José Saraiva 2604540.71
7 Shu Ito 2458535.61
8 Tsvi Reiter 2315185.61
9 Rachel Valdez 1827066.71
10 Tete Mensa-Annan 1576562.19
11 David Campbell 1573012.93
12 Garrett Vargas 1453719.46
13 Lynn Tsoflias 1421810.92
14 Pamela Ansman-Wolfe 1352577.13
Có một tổng quan tốt về các kỹ thuật phân trang khác nhau tại http://www.codeproject.com/KB/aspnet/PagingLarge.aspx
Tôi đã sử dụng phương pháp ROWCOUNT khá thường xuyên với SQL Server 2000 (cũng sẽ hoạt động với 2005 & 2008, chỉ đo hiệu suất so với ROW_NUMBER), nó nhanh như chớp, nhưng bạn cần chắc chắn rằng (các) cột được sắp xếp có (hầu hết) ) các giá trị duy nhất.
Đối với SQL Server 2000, bạn có thể mô phỏng ROW_NUMBER () bằng cách sử dụng biến bảng với cột IDENTITY:
DECLARE @pageNo int -- 1 based
DECLARE @pageSize int
SET @pageNo = 51
SET @pageSize = 20
DECLARE @firstRecord int
DECLARE @lastRecord int
SET @firstRecord = (@pageNo - 1) * @pageSize + 1 -- 1001
SET @lastRecord = @firstRecord + @pageSize - 1 -- 1020
DECLARE @orderedKeys TABLE (
rownum int IDENTITY NOT NULL PRIMARY KEY CLUSTERED,
TableKey int NOT NULL
)
SET ROWCOUNT @lastRecord
INSERT INTO @orderedKeys (TableKey) SELECT ID FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
SET ROWCOUNT 0
SELECT t.*
FROM Orders t
INNER JOIN @orderedKeys o ON o.TableKey = t.ID
WHERE o.rownum >= @firstRecord
ORDER BY o.rownum
Cách tiếp cận này có thể được mở rộng thành các bảng có các phím nhiều cột và nó không phải chịu chi phí hiệu năng khi sử dụng OR (bỏ qua việc sử dụng chỉ mục). Nhược điểm là lượng không gian tạm thời được sử dụng hết nếu tập dữ liệu rất lớn và một ở gần trang cuối cùng. Tôi đã không kiểm tra hiệu suất con trỏ trong trường hợp đó, nhưng nó có thể tốt hơn.
Lưu ý rằng phương pháp này có thể được tối ưu hóa cho trang dữ liệu đầu tiên. Ngoài ra, ROWCOUNT đã được sử dụng do TOP không chấp nhận một biến trong SQL Server 2000.
Cách tốt nhất để phân trang trong máy chủ sql 2012 là sử dụng offset và tìm nạp tiếp theo trong một thủ tục được lưu trữ. Từ khóa OFFSET - Nếu chúng tôi sử dụng offset theo thứ tự theo mệnh đề thì truy vấn sẽ bỏ qua số lượng bản ghi mà chúng tôi đã chỉ định trong OFFSET n Rows.
FETCH TIẾP THEO Từ khóa - Khi chúng tôi sử dụng Fetch Next với mệnh đề theo thứ tự, nó sẽ trả về không có hàng nào bạn muốn hiển thị trong phân trang, không có Offset thì SQL sẽ phát sinh lỗi. đây là ví dụ được đưa ra dưới đây.
create procedure sp_paging
(
@pageno as int,
@records as int
)
as
begin
declare @offsetcount as int
set @offsetcount=(@pageno-1)*@records
select id,bs,variable from salary order by id offset @offsetcount rows fetch Next @records rows only
end
bạn có thể thực hiện nó như sau.
exec sp_paging 2,3
Đây là những giải pháp của tôi để phân trang kết quả của truy vấn trong phía máy chủ SQL. các cách tiếp cận này khác nhau giữa SQL Server 2008 và 2012. Ngoài ra, tôi đã thêm khái niệm lọc và đặt hàng bằng một cột. Nó rất hiệu quả khi bạn phân trang và lọc và đặt hàng trong Gridview của bạn.
Trước khi kiểm tra, bạn phải tạo một bảng mẫu và chèn một số hàng trong bảng này: (Trong thế giới thực, bạn phải thay đổi mệnh đề Where xem xét các trường bảng của bạn và có thể bạn có một số tham gia và truy vấn phụ trong phần chính của lựa chọn)
Create Table VLT
(
ID int IDentity(1,1),
Name nvarchar(50),
Tel Varchar(20)
)
GO
Insert INTO VLT
VALUES
('NAME' + Convert(varchar(10),@@identity),'FAMIL' + Convert(varchar(10),@@identity))
GO 500000
Trong tất cả các mẫu này, tôi muốn truy vấn 200 hàng trên mỗi trang và tôi đang tìm nạp hàng cho số trang 1200.
Trong máy chủ SQL 2008, bạn có thể sử dụng khái niệm CTE. Do đó, tôi đã viết hai loại truy vấn cho máy chủ SQL 2008+
- Máy chủ SQL 2008 trở lên
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
) AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
GO
Và giải pháp thứ hai với CTE trong máy chủ SQL 2008+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
- Máy chủ SQL 2012+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN Data.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN Data.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN Data.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN Data.Tel END ASC
OFFSET @PageSize * (@PageNumber - 1) ROWS FETCH NEXT @PageSize ROWS ONLY;
Trường hợp sử dụng khôn ngoan sau đây dường như là dễ sử dụng và nhanh chóng. Chỉ cần đặt số trang.
use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6;
with result as(
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
)
select SalesOrderDetailID, SalesOrderID, ProductID from result
WHERE result.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
cũng không có CTE
use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6
SELECT SalesOrderDetailID, SalesOrderID, ProductID
FROM (
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
) AS SOD
WHERE SOD.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
Vâng, tôi đã sử dụng các truy vấn mẫu sau trong cơ sở dữ liệu SQL 2000 của tôi, nó hoạt động tốt cho SQL 2005 quá. Sức mạnh mà nó mang lại cho bạn là thứ tự động bằng cách sử dụng nhiều cột. Tôi nói với bạn ... điều này là mạnh mẽ :)
ALTER PROCEDURE [dbo].[RE_ListingReports_SelectSummary]
@CompanyID int,
@pageNumber int,
@pageSize int,
@sort varchar(200)
AS
DECLARE @sql nvarchar(4000)
DECLARE @strPageSize nvarchar(20)
DECLARE @strSkippedRows nvarchar(20)
DECLARE @strFields nvarchar(4000)
DECLARE @strFilter nvarchar(4000)
DECLARE @sortBy nvarchar(4000)
DECLARE @strFrom nvarchar(4000)
DECLARE @strID nvarchar(100)
If(@pageNumber < 0)
SET @pageNumber = 1
SET @strPageSize = CAST(@pageSize AS varchar(20))
SET @strSkippedRows = CAST(((@pageNumber - 1) * @pageSize) AS varchar(20))-- For example if pageNumber is 5 pageSize is 10, then SkippedRows = 40.
SET @strID = 'ListingDbID'
SET @strFields = 'ListingDbID,
ListingID,
[ExtraRoom]
'
SET @strFrom = ' vwListingSummary '
SET @strFilter = ' WHERE
CompanyID = ' + CAST(@CompanyID As varchar(20))
End
SET @sortBy = ''
if(len(ltrim(rtrim(@sort))) > 0)
SET @sortBy = ' Order By ' + @sort
-- Total Rows Count
SET @sql = 'SELECT Count(' + @strID + ') FROM ' + @strFROM + @strFilter
EXEC sp_executesql @sql
--// This technique is used in a Single Table pagination
SET @sql = 'SELECT ' + @strFields + ' FROM ' + @strFROM +
' WHERE ' + @strID + ' IN ' +
' (SELECT TOP ' + @strPageSize + ' ' + @strID + ' FROM ' + @strFROM + @strFilter +
' AND ' + @strID + ' NOT IN ' + '
(SELECT TOP ' + @strSkippedRows + ' ' + @strID + ' FROM ' + @strFROM + @strFilter + @SortBy + ') '
+ @SortBy + ') ' + @SortBy
Print @sql
EXEC sp_executesql @sql
Phần tốt nhất là sp_executesql lưu trữ các cuộc gọi sau này, miễn là bạn truyền cùng một tham số tức là tạo cùng một văn bản sql.
CREATE view vw_sppb_part_listsource as
select row_number() over (partition by sppb_part.init_id order by sppb_part.sppb_part_id asc ) as idx, * from (
select
part.SPPB_PART_ID
, 0 as is_rev
, part.part_number
, part.init_id
from t_sppb_init_part part
left join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
where prev.SPPB_PART_ID is null
union
select
part.SPPB_PART_ID
, 1 as is_rev
, prev.part_number
, part.init_id
from t_sppb_init_part part
inner join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
) sppb_part
sẽ khởi động lại idx khi nói đến init_id khác
Đối với ROW_NUMBER
kỹ thuật, nếu bạn không có cột sắp xếp để sử dụng, bạn có thể sử dụng CURRENT_TIMESTAMP
như sau:
SELECT TOP 20
col1,
col2,
col3,
col4
FROM (
SELECT
tbl.col1 AS col1
,tbl.col2 AS col2
,tbl.col3 AS col3
,tbl.col4 AS col4
,ROW_NUMBER() OVER (
ORDER BY CURRENT_TIMESTAMP
) AS sort_row
FROM dbo.MyTable tbl
) AS query
WHERE query.sort_row > 10
ORDER BY query.sort_row
Điều này đã làm việc tốt cho tôi khi tìm kiếm trên các kích thước bảng thậm chí lên tới 700.000.
Điều này lấy các bản ghi từ 11 đến 30.
create PROCEDURE SP_Company_List (@pagesize int = -1 ,@pageindex int= 0 ) > AS BEGIN SET NOCOUNT ON; select Id , NameEn from Company ORDER by Id ASC OFFSET (@pageindex-1 )* @pagesize ROWS FETCH NEXt @pagesize ROWS ONLY END GO
DECLARE @return_value int EXEC @return_value = [dbo].[SP_Company_List] @pagesize = 1 , > @pageindex = 2 SELECT 'Return Value' = @return_value GO
Bit này cung cấp cho bạn khả năng phân trang bằng SQL Server và các phiên bản mới hơn của MySQL và mang tổng số hàng trong mỗi hàng. Sử dụng khóa pimary của bạn để đếm số lượng hàng duy nhất.
WITH T AS
(
SELECT TABLE_ID, ROW_NUMBER() OVER (ORDER BY TABLE_ID) AS RN
, (SELECT COUNT(TABLE_ID) FROM TABLE) AS TOTAL
FROM TABLE (NOLOCK)
)
SELECT T2.FIELD1, T2.FIELD2, T2.FIELD3, T.TOTAL
FROM TABLE T2 (NOLOCK)
INNER JOIN T ON T2.TABLE_ID=T.TABLE_ID
WHERE T.RN >= 100
AND T.RN < 200
Đây là một bản sao của một người già câu hỏi 2012 SO: cách hiệu quả để thực hiện phân trang
TỪ [TableX] ĐẶT HÀNG B [NG [FieldX] OFFSET 500 ROWS FETCH TIẾP THEO 100 ROWS CHỈ
Ở đây chủ đề được thảo luận chi tiết hơn, và với các phương pháp thay thế.
Bạn đã không chỉ định ngôn ngữ cũng như trình điều khiển bạn đang sử dụng. Vì vậy, tôi đang mô tả nó một cách trừu tượng.