Apa cara terbaik untuk memberi paginasi hasil di SQL Server

474

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

Panagiotis Korros
sumber
26
Saya selalu bertanya-tanya mengapa mereka tidak hanya mendukung menentukan offset sebagai bagian dari TOP (seperti dukungan MySQL / Posgresql dengan LIMIT / OFFSET). Misalnya, mereka bisa saja memiliki sintaks "SELECT TOP x, y ...." di mana x = jumlah baris, y = mulai offset. Itu juga akan kompatibel ke belakang.
gregmac
3
hei, aku juga ... Implementasi pagination sql 2005 itu benar-benar sangat akward ...
opensas
6
@gregmac - Sql Server 2012 memang memiliki batas / offset sekarang.
OO
2
Solusi yang diterima tidak menunjukkan bagaimana itu adalah cara terbaik (kinerja bijaksana). Adakah data yang mendukungnya pada kumpulan data besar?
OO
3
@OO: Patokan yang baik dapat ditemukan di sini: 4guysfromrolla.com/webtech/042606-1.shtml . Namun, metode pencarian akan mengungguli pagination berbasis offset.
Lukas Eder

Jawaban:

465

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.

mdb
sumber
37
Hanya untuk dicatat bahwa ROW_NUMBER () tidak ada di SQL Server 2000
John Hunter
6
apakah ini mengembalikan semua baris dari permintaan dalam & kemudian memfilter berdasarkan permintaan luar? untuk contoh: permintaan dalam negeri mengembalikan 100.000 & permintaan luar hanya mengembalikan 20.
SoftwareGeek
2
@SoftwareGeek: anggap sebagai subquery (permintaan dalam) yang mengembalikan aliran, yang kemudian dibaca sampai klausa WHERE luar terpenuhi. Bagaimana baris terlibat dengan itu, sepenuhnya bergantung pada kueri, tetapi pengoptimal umumnya melakukan pekerjaan yang sangat baik dalam meminimalkan angka itu. Menggunakan penampil rencana eksekusi grafis di SQL Server Management Studio (menggunakan Query / Include Actual Execution Plan) sangat mendidik dalam hal itu.
mdb
2
ok, bagaimana jika Anda mendapatkan dublicated di inner select (seperti ketika Anda memiliki inner join) bagaimana Anda menggunakan yang berbeda karena RowNumber berbeda dan tidak berfungsi
user217648
10
Microsoft menambahkan fitur baru ke SQL 2012 yang membuat pagination mirip dengan MySQL. Ikuti tautan ini untuk mempelajari caranya. Artikel yang menarik: dbadiaries.com/...
Arash
512

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;

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql#using-offset-and-fetch-to-limit-the-rows- dikembalikan

Poin-poin penting untuk dipertimbangkan ketika menggunakannya:

  • ORDER BYwajib menggunakan OFFSET ... FETCHklausa.
  • OFFSETklausa wajib dengan FETCH. Anda tidak dapat menggunakan ORDER BY ... FETCH.
  • TOPtidak dapat digabungkan dengan OFFSETdan FETCHdalam ekspresi kueri yang sama.
Bekzbek
sumber
12
Masih menunggu LISTAGG()/ GROUP_CONCAT().
Bacon Bits
1
@BaconBits Lihat jawaban ini untuk cara licik melakukannya dengan FOR XML: stackoverflow.com/a/273330/429949
Richard Marskell - Drackir
1
@ RichardMarskell-Drackir Ada banyak masalah dengan 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.
Bacon Bits
4
Sayang perf ini sangat buruk mssqlgirl.com/...
Jon
5
@ Jon, posting blog yang tertaut itu tidak representatif, dalam arti ia membuat perbandingan berdasarkan mengembalikan hasil halaman dengan mencari nilai-nilai kolom id.
Noel Abrahams
103

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

"Mencari predikat"

Nilai @previousScoredan @previousPlayerIdadalah nilai masing-masing dari catatan terakhir dari halaman sebelumnya. Ini memungkinkan Anda untuk mengambil halaman "selanjutnya". Jika ORDER BYarahnya 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 .

Total catatan sebelum pagination

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(*).

Lukas Eder
sumber
2
@ user960567: Dalam hal kinerja, paging keyset akan selalu mengalahkan paging offset, tidak peduli apakah Anda menerapkan paging offset dengan standar SQL OFFSET .. FETCH, atau dengan ROW_NUMBER()trik sebelumnya .
Lukas Eder
21
Saya memiliki tiga masalah dengan metode pencarian. [1] Seorang pengguna tidak dapat melompat ke halaman. [2] itu mengasumsikan kunci berurutan yaitu jika seseorang menghapus sekitar 3 baris, maka saya mendapatkan halaman 7 item, bukan 10. RowNumbermemberi saya 10 item yang konsisten per halaman. [3] itu tidak berfungsi dengan kisi-kisi yang ada yang menganggap pagenumberdan pagesize.
Rebecca
7
@Junto: Paging keyset tidak cocok untuk semua kasus. Jelas bukan untuk kisi-kisi data. Tapi itu sempurna untuk skenario seperti pengguliran halaman umpan Facebook yang tak terbatas. Tidak masalah jika posting baru ditambahkan di bagian atas, posting feed Anda berikutnya akan ditambahkan dengan benar ke bawah saat Anda menggulir ke bawah. Contoh penggunaan sempurna untuk ini ... Hal seperti itu akan jauh lebih sulit untuk diterapkan menggunakan batas offset / pengambilan hanya menggunakan angka.
Robert Koritnik
4
Saya harus setuju dengan Junto. Metode ini benar-benar mengesampingkan klien yang memiliki ui pagination cukup standar dari "Sebelumnya 1 2 3 (4) 5 6 Berikutnya" di mana pengguna dapat melompat maju. Ini bukan kasus tepi dalam pengalaman saya ...
AaronHS
3
Artikel pagination Keyset di sini
Stphane
31

Dari SQL Server 2012, kita dapat menggunakan OFFSETdan FETCH NEXTKlausul 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;

TechNet: Paging Query dengan SQL Server

Mohan
sumber
jawaban paling akurat dalam uji coba ini
Vikrant
17

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
Dinesh Rabara
sumber
15

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.

liggett78
sumber
1
Menariknya, artikel itu tidak menyebutkan metode pencarian , yang mampu melakukan paging dalam waktu yang konstan ... Masih artikel yang bagus
Lukas Eder
6

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.

Thomas S. Trias
sumber
3

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
Debendra Dash
sumber
2

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;
Ardalan Shahgholi
sumber
1

Coba pendekatan ini:

SELECT TOP @offset a.*
FROM (select top @limit b.*, COUNT(*) OVER() totalrows 
        from TABLENAME b order by id asc) a
ORDER BY id desc;
fatlion
sumber
1

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)
Guntur
sumber
1
Apa yang dilakukan di mana 1 = 1 Pak?
Errol Paleracio
0

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.

Jalal El-Shaer
sumber
0
   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

Aden
sumber
0

Untuk ROW_NUMBERtekniknya, jika Anda tidak memiliki kolom penyortiran untuk digunakan, Anda dapat menggunakan CURRENT_TIMESTAMPsebagai 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.

pengguna919426
sumber
Sebagai praktik yang baik, dengan pagination Anda harus mencoba memesan dengan seperangkat kolom yang unik di set hasil karena pesanan tidak boleh dianggap sebagai dijamin.
Arin Taylor
2
Ini mengambil catatan 11 hingga 30.
Ardalan Shahgholi
0
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
salem albadawi
sumber
0

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
Alex M.
sumber
Bisakah Anda meninggalkan komentar yang menjelaskan apa yang kode Anda lakukan?
Doug F
0

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.

dpopov
sumber
0

Mulai 2012 dan selanjutnya kita bisa menggunakan OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

Damitha
sumber
-19

Anda tidak menentukan bahasa atau driver yang Anda gunakan. Karena itu saya jelaskan secara abstrak.

  • Buat resultset / dataset yang dapat digulir. Ini membutuhkan primer di atas meja
  • lompat sampai akhir
  • minta jumlah baris
  • lompat ke awal halaman
  • gulir melintasi baris sampai akhir halaman
Horcrux7
sumber