Setara dengan LIMIT dan OFFSET untuk SQL Server?

172

Di PostgreSQL ada Limitdan Offsetkata kunci yang akan memungkinkan pagination set hasil yang sangat mudah.

Apa sintaks yang setara untuk SQL Server?

Earlz
sumber
Untuk sql server 2012, fitur ini diimplementasikan dengan cara mudah. Lihat jawaban saya
Somnath Muluk
Terima kasih telah mengajukan pertanyaan ini, kami dipaksa untuk beralih dari MySQL ke MsSQL :(
tempcke
Anda dapat menggunakan offset dan mengambil pernyataan berikutnya di SQL server dengan urutan demi klausa. Cobalah youtu.be/EqHkAiiBwPc
Amresh Kumar Singh

Jawaban:

139

Setara dengan LIMITitu SET ROWCOUNT, tetapi jika Anda ingin pagination generik lebih baik menulis kueri seperti ini:

;WITH Results_CTE AS
(
    SELECT
        Col1, Col2, ...,
        ROW_NUMBER() OVER (ORDER BY SortCol1, SortCol2, ...) AS RowNum
    FROM Table
    WHERE <whatever>
)
SELECT *
FROM Results_CTE
WHERE RowNum >= @Offset
AND RowNum < @Offset + @Limit

Keuntungannya di sini adalah parameterisasi offset dan batas jika Anda memutuskan untuk mengubah opsi paging Anda (atau mengizinkan pengguna untuk melakukannya).

Catatan: yang @Offsetparameter harus menggunakan satu berbasis pengindeksan untuk ini daripada normal pengindeksan berbasis nol.

Aaronaught
sumber
22
Tua sekarang. Sql Server 2012 dan yang lebih baru mendukung OFFSET / FETCH
Joel Coehoorn
31
@ JoelCoehoorn Tidak tua. Saya baru saja ditugaskan untuk memproyeksikan menggunakan SLQ Server 2008 setelah hanya menggunakan mysql di masa lalu ...
Cthulhu
Ini cukup bagus tetapi perlu sedikit WHERE RowNum >= (@Offset + 1)
disesuaikan
5
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified. MSSQL2008 R2.
Paul
2
@Aaronaught Jika Tablecatatan saya memiliki 200 ribu, itu akan mengambil semuanya terlebih dahulu, lalu menerapkan batas? Apakah kueri ini efisien?
Jigar
231

Fitur ini sekarang menjadi mudah di SQL Server 2012. Ini berfungsi dari SQL Server 2012 dan seterusnya.

Batasi dengan offset untuk memilih 11 hingga 20 baris di SQL Server:

SELECT email FROM emailTable 
WHERE user_id=3
ORDER BY Id
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
  • OFFSET: jumlah baris yang dilewati
  • NEXT: diperlukan jumlah baris berikutnya

Referensi: https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

Somnath Muluk
sumber
4
Apakah ada equiv SQL_CALC_FOUND_ROWSsaat menggunakan ini?
Petah
1
@Petah @@ Rowcount akan memberi Anda pendapat saya
Rob Sedgwick
GOTCHA: Anda tidak dapat menggunakan ini dari dalam CTE. Itu harus digunakan dalam permintaan utama. Saya ingin membatasi jumlah baris yang dikembalikan (pagination) dan kemudian melakukan perhitungan mahal hingga 10 atau lebih baris yang dikembalikan, daripada menentukan baris, melakukan perhitungan mahal, dan kemudian melewati / mengambil apa yang saya butuhkan. @ Jawaban Aaronaught akan bekerja untuk mereka yang perlu membatasi baris dalam CTE.
Derreck Dean
@Somnath Muluk Offset dan pengambilan ini membutuhkan banyak waktu untuk volume data contoh yang lebih tinggi dengan offset 1000000. Bagaimana saya bisa mengatasinya.
Saroj Shrestha
1
@SarojShrestha: Ini bukan Offset dan Fetch masalah. Anda harus mengunjungi kembali arsitektur meja Anda sekarang. Pertimbangkan Mempartisi tabel, baris data Anda dan tipe kolom yang berbeda serta ukuran tabel total, pertimbangkan untuk mengarsipkan beberapa baris jika tidak diperlukan secara teratur, periksa spesifikasi server Anda.
Somnath Muluk
23
select top {LIMIT HERE} * from (
      select *, ROW_NUMBER() over (order by {ORDER FIELD}) as r_n_n 
      from {YOUR TABLES} where {OTHER OPTIONAL FILTERS}
) xx where r_n_n >={OFFSET HERE}

Catatan: Solusi ini hanya akan berfungsi di SQL Server 2005 atau lebih baru, karena ini adalah saat ROW_NUMBER()diimplementasikan.

jorgeu
sumber
Saya telah menggunakan permintaan ini untuk sementara waktu sekarang dan ini berfungsi dengan baik, jadi terima kasih untuk itu. Saya hanya ingin tahu apa yang mewakili 'xx'?
Urbley
sub kueri membutuhkan nama. karena saya tidak menggunakannya, cukup taruh xx di sana
jorgeu
2
Xx hanyalah alias tabel. Mungkin sedikit lebih jelas jika Anda berkataAS xx
Concrete Gannet
ada yang tahu bagaimana cara bergabung dengan pertanyaan ini?
Drenyl
12

Anda dapat menggunakan ROW_NUMBER dalam Ekspresi Tabel Umum untuk mencapai ini.

;WITH My_CTE AS
(
     SELECT
          col1,
          col2,
          ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
)
SELECT
     col1,
     col2
FROM
     My_CTE
WHERE
     row_number BETWEEN @start_row AND @end_row
Tom H
sumber
4

Bagi saya penggunaan OFFSET dan FETCH bersama lambat, jadi saya menggunakan kombinasi TOP dan OFFSET seperti ini (yang lebih cepat):

SELECT TOP 20 * FROM (SELECT columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

Catatan: Jika Anda menggunakan TOP dan OFFSET secara bersamaan dalam permintaan yang sama seperti:

SELECT TOP 20 columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS

Kemudian Anda mendapatkan kesalahan, jadi untuk menggunakan TOP dan OFFSET bersama-sama Anda harus memisahkannya dengan sub-kueri.

Dan jika Anda perlu menggunakan SELECT DISTINCT maka kueri seperti:

SELECT TOP 20 FROM (SELECT DISTINCT columname1, columname2
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

Catatan: Penggunaan SELECT ROW_NUMBER dengan DISTINCT tidak berhasil untuk saya.

sebasdev
sumber
1
Saya mendapatkan "A TOP tidak dapat digunakan dalam kueri atau sub-kueri yang sama seperti OFFSET."
MichaelRushton
Anda benar @MichaelRushton, tidak dapat digunakan dalam kueri yang sama atau dalam sub-kueri yang sama, maka Anda harus menggunakan sub-kueri untuk memisahkannya. Jadi, jika Anda memiliki SQL like SELECT TOP 20 id FROM table1 where id > 10 order by date OFFSET 20 rows, Anda harus mengubahnya seperti SELECT TOP 20 * FROM (SELECT id FROM table1 where id > 10 order by date OFFSET 20 ROWS) t1. Saya akan mengedit jawaban saya. Terima kasih dan permisi Bahasa Inggris saya.
sebasdev
2

Sampel lain:

declare @limit int 
declare @offset int 
set @offset = 2;
set @limit = 20;
declare @count int
declare @idxini int 
declare @idxfim int 
select @idxfim = @offset * @limit
select @idxini = @idxfim - (@limit-1);
WITH paging AS
    (
        SELECT 
             ROW_NUMBER() OVER (order by object_id) AS rowid, *
        FROM 
            sys.objects 
    )
select *
    from 
        (select COUNT(1) as rowqtd from paging) qtd, 
            paging 
    where 
        rowid between @idxini and @idxfim
    order by 
        rowid;
sillyim
sumber
15
Saya menghapus pidato kebencian anti-microsoft Anda. Jangan membahas perang suci di sini; jawab saja dan ajukan pertanyaan dengan cara yang tidak subyektif.
Earlz
2

Di sini ada seseorang yang menceritakan tentang fitur ini di sql 2011, sayangnya mereka memilih kata kunci yang sedikit berbeda "OFFSET / FETCH" tetapi tidak standar maka ok.

keepkeywordspleeeease
sumber
2

Menambahkan sedikit variasi pada solusi Aaronaught, saya biasanya menentukan nomor halaman (@PageNum) dan ukuran halaman (@PageSize). Dengan cara ini setiap klik acara acara hanya mengirimkan nomor halaman yang diminta bersama dengan ukuran halaman yang dapat dikonfigurasi:

begin
    with My_CTE  as
    (
         SELECT col1,
              ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
    )
    select * from My_CTE
            WHERE RowNum BETWEEN (@PageNum - 1) * (@PageSize + 1) 
                              AND @PageNum * @PageSize

end
Tom
sumber
2

Yang paling dekat yang bisa saya lakukan adalah

select * FROM( SELECT *, ROW_NUMBER() over (ORDER BY ID ) as ct from [db].[dbo].[table] ) sub where ct > fromNumber  and ct <= toNumber

Saya kira mirip dengan select * from [db].[dbo].[table] LIMIT 0, 10

pengguna2991730
sumber
2
-- @RowsPerPage  can be a fixed number and @PageNumber number can be passed 
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 2

SELECT *

FROM MemberEmployeeData

ORDER BY EmployeeNumber

OFFSET @PageNumber*@RowsPerPage ROWS

FETCH NEXT 10 ROWS ONLY
shakeel
sumber
Bekerja untuk Microsoft SQL Server 13.x Terima kasih banyak.
Shubham Arya
1
select top (@TakeCount) * --FETCH NEXT
from(
    Select  ROW_NUMBER() OVER (order by StartDate) AS rowid,*
    From YourTable
)A
where Rowid>@SkipCount --OFFSET
Barny
sumber
1
@nombre_row :nombre ligne par page  
@page:numero de la page

//--------------code sql---------------

declare  @page int,@nombre_row int;
    set @page='2';
    set @nombre_row=5;
    SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY etudiant_ID ) AS RowNum, *
      FROM      etudiant

    ) AS RowConstrainedResult
WHERE   RowNum >= ((@page-1)*@nombre_row)+1
    AND RowNum < ((@page)*@nombre_row)+1
ORDER BY RowNum
noureddine ahmer el kaab
sumber
1

Karena belum ada yang memberikan kode ini:

SELECT TOP @limit f1, f2, f3...
FROM t1
WHERE c1 = v1, c2 > v2...
AND
    t1.id NOT IN
        (SELECT TOP @offset id
         FROM t1
         WHERE c1 = v1, c2 > v2...
         ORDER BY o1, o2...)
ORDER BY o1, o2...

Poin-poin penting:

  • ORDER BY harus identik
  • @limit dapat diganti dengan jumlah hasil yang akan diambil,
  • @offset adalah jumlah hasil untuk dilewati
  • Silakan bandingkan kinerja dengan solusi sebelumnya karena mereka mungkin lebih efisien
  • solusi ini duplikat wheredan order byklausa, dan akan memberikan hasil yang salah jika mereka tidak sinkron
  • di sisi lain order byada secara eksplisit jika itu yang dibutuhkan
przemo_li
sumber
1

Khusus untuk SQL-SERVER Anda dapat mencapainya dengan berbagai cara. Untuk memberikan contoh nyata, kami mengambil tabel Pelanggan di sini.

Contoh 1: Dengan "SET ROWCOUNT"

SET ROWCOUNT 10
SELECT CustomerID, CompanyName from Customers
ORDER BY CompanyName

Untuk mengembalikan semua baris, atur ROWCOUNT ke 0

SET ROWCOUNT 0  
SELECT CustomerID, CompanyName from Customers
    ORDER BY CompanyName

Contoh 2: Dengan "ROW_NUMBER dan OVER"

With Cust AS
( SELECT CustomerID, CompanyName,
ROW_NUMBER() OVER (order by CompanyName) as RowNumber 
FROM Customers )
select *
from Cust
Where RowNumber Between 0 and 10

Contoh 3: Dengan "OFFSET dan FETCH", Tetapi dengan "ORDER BY" ini wajib

SELECT CustomerID, CompanyName FROM Customers
ORDER BY CompanyName
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY

Semoga ini bisa membantu Anda.

Humayoun_Kabir
sumber
-1

Di SQL server Anda akan menggunakan TOP bersama dengan ROW_NUMBER ()

SQLMenace
sumber
-1

Karena, saya menguji lebih banyak skrip ini lebih bermanfaat dengan 1 juta catatan setiap halaman 100 catatan dengan pagination berfungsi lebih cepat PC saya mengeksekusi skrip ini 0 detik sementara dibandingkan dengan mysql memiliki batas sendiri dan mengimbangi sekitar 4,5 detik untuk mendapatkan hasilnya.

Seseorang mungkin kehilangan pemahaman Row_Number () selalu urutkan berdasarkan bidang tertentu. Jika kita perlu mendefinisikan hanya baris secara berurutan yang harus digunakan:

ROW_NUMBER () OVER (ORDER BY (SELECT NULL))

SELECT TOP {LIMIT} * FROM (
      SELECT TOP {LIMIT} + {OFFSET} ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ROW_NO,*
      FROM  {TABLE_NAME}
) XX WHERE ROW_NO > {OFFSET}

Menjelaskan:

  • {LIMIT}: Jumlah catatan untuk setiap halaman
  • {OFFSET}: Jumlah catatan lewati
Vanda Ros
sumber
2
Meskipun kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah akan sangat membantu untuk meningkatkan kualitas posting Anda, dan mungkin menghasilkan lebih banyak suara. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang. Harap edit jawaban Anda untuk menambahkan penjelasan dan berikan indikasi tentang batasan dan asumsi apa yang berlaku.
Brian