Apa cara terbaik (kinerja bijaksana) untuk hasil paginasi dalam SQL Server 2000, 2005, 2008, 2012 jika Anda juga ingin mendapatkan jumlah total hasil (sebelum paginasi)?
Apa cara terbaik (kinerja bijaksana) untuk hasil paginasi dalam SQL Server 2000, 2005, 2008, 2012 jika Anda juga ingin mendapatkan jumlah total hasil (sebelum paginasi)?
Jawaban:
Mendapatkan jumlah total hasil dan paginasi adalah dua operasi yang berbeda. Demi contoh ini, mari kita asumsikan bahwa kueri yang Anda hadapi adalah
SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
Dalam hal ini, Anda akan menentukan jumlah total hasil menggunakan:
SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'
... yang mungkin tampak tidak efisien, tetapi sebenarnya cukup performan, dengan asumsi semua indeks dll sudah diatur dengan benar.
Selanjutnya, untuk mendapatkan hasil yang sebenarnya dalam mode halaman, permintaan berikut akan paling efisien:
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
Ini akan mengembalikan baris 1-19 dari permintaan asli. Yang paling keren di sini, terutama untuk aplikasi web, adalah Anda tidak perlu mempertahankan status apa pun, kecuali nomor baris yang harus dikembalikan.
Akhirnya, Microsoft SQL Server 2012 dirilis, saya sangat suka kesederhanaannya untuk pagination, Anda tidak harus menggunakan pertanyaan kompleks seperti dijawab di sini.
Untuk mendapatkan 10 baris berikutnya jalankan saja query ini:
SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
Poin-poin penting untuk dipertimbangkan ketika menggunakannya:
ORDER BY
wajib menggunakan OFFSET ... FETCH
klausa.OFFSET
klausa wajib dengan FETCH
. Anda tidak dapat menggunakan ORDER BY ...
FETCH
.TOP
tidak dapat digabungkan dengan OFFSET
dan FETCH
dalam ekspresi kueri yang sama.LISTAGG()
/ GROUP_CONCAT()
.
FOR XML
: stackoverflow.com/a/273330/429949
FOR XML PATH ('')
. Pertama, ia menggantikan karakter kontrol XML dengan kode entitas XML. Harap Anda tidak memiliki <
, >
atau &
dalam data Anda! Kedua, FOR XML PATH ('')
digunakan dengan cara ini sebenarnya sintaksis tidak berdokumen. Anda seharusnya menentukan kolom bernama atau nama elemen pengganti. Tidak melakukan keduanya tidak ada dalam dokumen, berarti perilaku tersebut tidak dapat diandalkan. Ketiga, semakin kita menerima FOR XML PATH ('')
sintaks yang rusak , semakin kecil kemungkinannya bahwa MS benar-benar menyediakan fungsi nyata LISTAGG() [ OVER() ]
seperti yang mereka butuhkan.
Luar biasa, tidak ada jawaban lain yang menyebutkan cara tercepat untuk melakukan pagination di semua versi SQL Server. Offset bisa sangat lambat untuk nomor halaman besar seperti yang ditentukan di sini . Ada cara yang sama sekali berbeda, jauh lebih cepat untuk melakukan pagination dalam SQL. Ini sering disebut "mencari metode" atau "pagination keyset" seperti yang dijelaskan dalam posting blog ini di sini .
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
Nilai @previousScore
dan @previousPlayerId
adalah nilai masing-masing dari catatan terakhir dari halaman sebelumnya. Ini memungkinkan Anda untuk mengambil halaman "selanjutnya". Jika ORDER BY
arahnya ASC
, gunakan >
saja.
Dengan metode di atas, Anda tidak dapat langsung melompat ke halaman 4 tanpa terlebih dahulu mengambil 40 catatan sebelumnya. Namun seringkali, Anda tidak ingin melompat sejauh itu. Alih-alih, Anda mendapatkan kueri yang jauh lebih cepat yang mungkin dapat mengambil data dalam waktu konstan, tergantung pada pengindeksan Anda. Plus, halaman Anda tetap "stabil", tidak masalah jika data yang mendasarinya berubah (misalnya di halaman 1, saat Anda di halaman 4).
Ini adalah cara terbaik untuk mengimplementasikan pagination ketika malas memuat lebih banyak data dalam aplikasi web, misalnya.
Catatan, "metode pencarian" juga disebut pagination keyset .
Fungsi COUNT(*) OVER()
jendela akan membantu Anda menghitung jumlah total catatan "sebelum pagination". Jika Anda menggunakan SQL Server 2000, Anda harus menggunakan dua kueri untuk COUNT(*)
.
OFFSET .. FETCH
, atau dengan ROW_NUMBER()
trik sebelumnya .
RowNumber
memberi saya 10 item yang konsisten per halaman. [3] itu tidak berfungsi dengan kisi-kisi yang ada yang menganggap pagenumber
dan pagesize
.
Dari SQL Server 2012, kita dapat menggunakan OFFSET
dan FETCH NEXT
Klausul untuk mencapai pagination.
Coba ini, untuk SQL Server:
Dalam SQL Server 2012 fitur baru ditambahkan dalam klausa ORDER BY, untuk kueri pengoptimalan data yang ditetapkan, membuat pekerjaan lebih mudah dengan paging data bagi siapa saja yang menulis dalam T-SQL juga untuk seluruh Rencana Eksekusi di SQL Server.
Di bawah skrip T-SQL dengan logika yang sama dengan yang digunakan pada contoh sebelumnya.
--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 (Transact-SQL)
Mengembalikan nomor urut baris dalam partisi dari hasil yang ditetapkan, mulai dari 1 untuk baris pertama di setiap partisi.
Contoh berikut mengembalikan baris dengan angka 50 hingga 60 inklusif dalam urutan 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
Ada gambaran bagus tentang berbagai teknik paging di http://www.codeproject.com/KB/aspnet/PagingLarge.aspx
Saya telah menggunakan metode ROWCOUNT cukup sering sebagian besar dengan SQL Server 2000 (akan bekerja dengan 2005 & 2008 juga, hanya mengukur kinerja dibandingkan dengan ROW_NUMBER), sangat cepat, tetapi Anda perlu memastikan bahwa kolom yang disortir memiliki (kebanyakan) ) nilai unik.
Untuk SQL Server 2000 Anda dapat mensimulasikan ROW_NUMBER () menggunakan variabel tabel dengan kolom 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
Pendekatan ini dapat diperluas ke tabel dengan kunci multi-kolom, dan itu tidak menimbulkan kinerja overhead menggunakan OR (yang melompati penggunaan indeks). Kelemahannya adalah jumlah ruang sementara yang digunakan jika kumpulan data sangat besar dan satu berada di dekat halaman terakhir. Saya tidak menguji kinerja kursor dalam kasus itu, tetapi mungkin lebih baik.
Perhatikan bahwa pendekatan ini dapat dioptimalkan untuk halaman data pertama. Juga, ROWCOUNT digunakan karena TOP tidak menerima variabel dalam SQL Server 2000.
Cara terbaik untuk paging di sql server 2012 adalah dengan menggunakan offset dan mengambil berikutnya dalam prosedur tersimpan. Kata Kunci OFFSET - Jika kita menggunakan offset dengan urutan dengan klausa maka kueri akan melewati jumlah catatan yang kita tentukan di OFFSET dan Baris.
FETCH NEXT Keywords - Ketika kita menggunakan Fetch Next dengan pesanan dengan klausa hanya akan mengembalikan jumlah baris yang ingin Anda tampilkan dalam paging, tanpa Offset maka SQL akan menghasilkan kesalahan. di sini adalah contoh yang diberikan di bawah ini.
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
Anda dapat menjalankannya sebagai berikut.
exec sp_paging 2,3
Ini adalah solusi saya untuk mem-paging hasil query di sisi SQL server. pendekatan ini berbeda antara SQL Server 2008 dan 2012. Juga, saya telah menambahkan konsep penyaringan dan pesanan dengan satu kolom. Ini sangat efisien ketika Anda melakukan paging dan memfilter serta memesan di Gridview Anda.
Sebelum pengujian, Anda harus membuat satu tabel contoh dan memasukkan beberapa baris dalam tabel ini: (Di dunia nyata Anda harus mengubah Di mana klausa mempertimbangkan bidang tabel Anda dan mungkin Anda memiliki beberapa gabungan dan subquery di bagian utama pilih)
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
Dalam semua sampel ini, saya ingin meminta 200 baris per halaman dan saya mengambil baris untuk nomor halaman 1200.
Di SQL server 2008, Anda dapat menggunakan konsep CTE. Karena itu, saya telah menulis dua jenis kueri untuk SQL server 2008+
- SQL Server 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.
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
Dan solusi kedua dengan CTE di SQL server 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
- SQL Server 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;
Gunakan case bijaksana berikut ini tampaknya mudah digunakan dan cepat. Cukup atur nomor halaman.
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)
juga tanpa 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)
Yah saya telah menggunakan contoh permintaan berikut dalam database SQL 2000 saya, itu berfungsi dengan baik untuk SQL 2005 juga. Kekuatan yang diberikannya kepada Anda adalah urutan dinamis dengan menggunakan beberapa kolom. Saya katakan ... ini sangat ampuh :)
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
Bagian terbaiknya adalah sp_executesql cache panggilan kemudian, asalkan Anda melewati parameter yang sama yaitu menghasilkan teks sql yang sama.
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
akan memulai ulang idx ketika datang ke init_id yang berbeda
Untuk ROW_NUMBER
tekniknya, jika Anda tidak memiliki kolom penyortiran untuk digunakan, Anda dapat menggunakan CURRENT_TIMESTAMP
sebagai berikut:
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
Ini telah bekerja dengan baik bagi saya untuk pencarian di atas ukuran meja bahkan hingga 700.000.
Ini mengambil catatan 11 hingga 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 ini memberi Anda kemampuan untuk melakukan paginasi menggunakan SQL Server, dan versi MySQL yang lebih baru dan membawa jumlah total baris di setiap baris. Gunakan kunci pimary Anda untuk menghitung jumlah baris unik.
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
Ini adalah duplikat dari pertanyaan SO lama 2012: cara efisien untuk menerapkan paging
DARI [TableX] ORDER OLEH [FieldX] OFFSET 500 BARIS FETCH SELANJUTNYA 100 BARIS HANYA
Di sini topik dibahas secara lebih rinci, dan dengan pendekatan alternatif.
Anda tidak menentukan bahasa atau driver yang Anda gunakan. Karena itu saya jelaskan secara abstrak.