SQL Server'da sonuçları sayfalandırmanın en iyi yolu nedir


474

Toplam sonuç sayısını da (sayfalandırmadan önce) almak istiyorsanız SQL Server 2000, 2005, 2008, 2012'de sonuçları sayfalandırmanın en iyi yolu (performans açısından akıllıca) nedir?


26
Ben her zaman neden sadece bir parçası ofset belirleme (örneğin LIMS / OFFSET ile MySQL / Posgresql desteği gibi) desteklemiyor merak ettim. Örneğin, sadece "SELECT TOP x, y ...." sözdizimine sahip olabilirler; burada x = satır sayısı, y = başlangıç ​​ofseti. Ayrıca geriye dönük olarak uyumlu olacaktır.
gregmac

3
hey, ben de ...
sql'in

6
@gregmac - Sql Server 2012'de artık sınır / ofset var.
OO

2
Kabul edilen çözüm, en iyi yolun nasıl olduğunu göstermez (performans açısından). Büyük veri kümelerinde yedeklenen herhangi bir veri var mı?
OO

3
@OO: Burada iyi bir karşılaştırma ölçütü bulunabilir: 4guysfromrolla.com/webtech/042606-1.shtml . Bununla birlikte, seek yöntemi , ofset tabanlı sayfa numaralandırmadan daha iyi performans gösterir.
Lukas Eder

Yanıtlar:


465

Toplam sonuç sayısını elde etmek ve sayfalara ayırmak iki farklı işlemdir. Bu örnek uğruna, ele aldığınız sorgunun

SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate

Bu durumda, toplam sonuç sayısını kullanarak şunları belirlersiniz:

SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'

... verimsiz görünebilir, ancak aslında tüm dizinlerin vb.

Daha sonra, gerçek sonuçları tekrar disk belleği biçiminde almak için aşağıdaki sorgu en verimli olacaktır:

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

Bu, orijinal sorgunun 1-19. Satırlarını döndürür. Buradaki harika şey, özellikle web uygulamaları için, döndürülecek satır numaraları dışında herhangi bir durumu korumanız gerekmemesidir.


37
SQL Server 2000'de ROW_NUMBER () olmadığını unutmayın
John Hunter

6
bu, iç sorgudaki tüm satırları ve ardından dış sorguyu temel alan filtreyi döndürür mü? ex için: iç sorgu 100.000 ve dış sorgu yalnızca 20 döndürür.
SoftwareGeek

2
@SoftwareGeek: bir akışı döndüren alt sorgu (iç sorgu) olarak düşünün; bu daha sonra dış WHERE yan tümcesi karşılanana kadar okunur. Satırların buna nasıl dahil edileceği tamamen sorgulamaya bağlıdır, ancak optimizer genellikle bu sayıyı en aza indirgemek için çok iyi bir iş çıkarır. SQL Server Management Studio'da grafik yürütme planı görüntüleyicinin kullanılması (Sorgu / Gerçek Yürütme Planını İçer) kullanın.
MDB

2
Tamam, ne iç seçimde (iç birleşim varsa gibi)
yayımlanırsa

10
Microsoft, SQL 2012'ye sayfalandırmayı MySQL'e benzeyen yeni bir özellik ekledi. Nasıl yapılacağını öğrenmek için bu bağlantıyı takip edin. İlginç bir makale: dbadiaries.com/…
Arash

512

Son olarak, Microsoft SQL Server 2012 piyasaya sürüldü, bir sayfalama için basitliğini gerçekten seviyorum, burada cevaplanan gibi karmaşık sorgular kullanmak zorunda değilsiniz.

Sonraki 10 satırı almak için şu sorguyu çalıştırın:

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- iade

Kullanırken dikkat edilmesi gereken önemli noktalar:

  • ORDER BYOFFSET ... FETCHfıkra kullanmak zorunludur .
  • OFFSETcümlesi ile zorunludur FETCH. Kullanamazsın ORDER BY ... FETCH.
  • TOPile kombine edilebilir değildir OFFSETve FETCHaynı sorgu ifadesinde.

12
Yine bekleyen LISTAGG()/ ' GROUP_CONCAT().
Bacon Bits

1
@BaconBits Bunu yapmak için sinsi bir yol için bu cevaba bakınız FOR XML: stackoverflow.com/a/273330/429949
Richard Marskell - Drackir

1
@ RichardMarskell-Drackir ile ilgili birçok sorun var FOR XML PATH (''). İlk olarak, XML kontrol karakterlerini XML varlık kodlarıyla değiştirir. Eğer yoksa Umut <, >ya &da verilerde! İkincisi, FOR XML PATH ('')bu şekilde kullanılan aslında belgesiz sözdizimidir. Adlandırılmış bir sütun veya alternatif bir öğe adı belirtmeniz gerekiyor. Her ikisini de yapmak dokümanda değildir, yani davranış güvenilir değildir. Üçüncüsü, kırık FOR XML PATH ('')sözdizimini ne kadar çok kabul edersek , MS'in aslında ihtiyaç duydukları gibi gerçek bir LISTAGG() [ OVER() ] işlev sağlaması o kadar az olasıdır .
Bacon Bits

4
utanç perf çok kötü mssqlgirl.com/…
Jon

5
@Jon, bağlantılı blog yazısı temsili değildir, yani id sütununun değerlerine bakarak sayfa sonucunu döndürmeye dayalı karşılaştırmalar yapar.
Noel Abrahams

103

İnanılmaz bir şekilde, başka hiçbir yanıt tüm SQL Server sürümlerinde sayfalandırma yapmanın en hızlı yolundan bahsetmemiştir . Ofsetler, burada kıyaslandığı gibi büyük sayfa numaraları için çok yavaş olabilir . SQL'de sayfalandırma yapmanın tamamen farklı, çok daha hızlı bir yolu vardır. Buna genellikle bu blog yazısında açıklandığı gibi "arama yöntemi" veya "tuş takımı sayfalaması" denir .

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

"Arama emri"

@previousScoreVe @previousPlayerIddeğerler önceki sayfadan son kaydın ilgili değerlerdir. Bu, "sonraki" sayfayı getirmenizi sağlar. Eğer ORDER BYyön ise ASC, sadece kullanım >yerine.

Yukarıdaki yöntemle, önceki 40 kaydı ilk getirmeden hemen sayfa 4'e atlayamazsınız. Ama çoğu zaman, o kadar ileri atlamak istemezsiniz. Bunun yerine, dizine ekleme işleminize bağlı olarak verileri sabit sürede alabilecek çok daha hızlı bir sorgu alırsınız. Ayrıca, temel verilerin değişmesi fark etmeksizin sayfalarınız "sabit" kalır (örneğin, sayfa 4'teyken sayfa 1'de).

Örneğin, web uygulamalarına daha fazla veri tembel olarak yüklendiğinde sayfalandırmanın en iyi yolu budur.

Not, "arama yöntemi" tuş takımı sayfalama olarak da adlandırılır .

Sayfalandırmadan önceki toplam kayıtlar

COUNT(*) OVER()Pencere fonksiyonu "pagination önce" toplam kayıt sayısını saymak yardımcı olacaktır. SQL Server 2000 kullanıyorsanız, için iki sorgu başvurmanız gerekir COUNT(*).


2
@ user960567: Performans açısından, SQL standardı OFFSET .. FETCHveya önceki ROW_NUMBER()hilelerle ofset sayfalama uygulasanız da, tuş takımı sayfalama her zaman ofset sayfalamasını geçecektir .
Lukas Eder

21
Arama yöntemiyle ilgili üç sorunum var. [1] Bir kullanıcı sayfaya atlayamaz. [2] sıralı anahtarlar varsayar, yani birisi 3 satır silerse, o zaman 10 yerine 7 öğeden oluşan bir sayfa alıyorum. RowNumberBana sayfa başına tutarlı 10 öğe verir. [3] pagenumberve varsayılan var olan ızgaralarla çalışmaz pagesize.
Rebecca

7
@Junto: tuş takımı sayfalaması tüm durumlar için uygun değildir. Kesinlikle veri ızgaraları için değil. Ancak Facebook feed sayfasının sonsuz kaydırılması gibi senaryolar için mükemmeldir. En üste yeni yayınlar eklenip eklenmediği önemli değil, aşağıya doğru ilerlerken sonraki yayın yayınlarınız aşağıya doğru şekilde eklenecektir. Bunun için mükemmel kullanım örneği ... Böyle bir şey, sadece sayıları kullanarak ofset limiti / getirme kullanarak uygulamak çok daha zor olacaktır.
Robert Koritnik

4
Junto ile hemfikirim. Bu yöntem, kullanıcıların ileri atlayabileceği "Önceki 1 2 3 (4) 5 6 İleri" nin oldukça standart bir sayfalama kullanıcı arayüzüne sahip bir istemciyi tamamen ortadan kaldırır. Bu benim tecrübelerime göre bir son durum değil ...
AaronHS


31

SQL Server 2012'den, sayfalamayı elde etmek için OFFSETve FETCH NEXTClause kullanabiliriz .

SQL Server için şunu deneyin:

SQL Server 2012'de, ORDER BY deyiminde, ayarlanan verilerin optimizasyonunu sorgulamak ve SQL Server'daki tüm Yürütme Planı için T-SQL'de yazan herkes için veri sayfalamasıyla çalışmayı kolaylaştırmak için yeni bir özellik eklendi.

Önceki örnekte kullanılanla aynı mantığa sahip T-SQL komut dosyasının altında.

--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: Sorguyu SQL Server ile Çağrı


Bu denemede en doğru cevap
Vikrant

17

MSDN: ROW_NUMBER (Transact-SQL)

Her bölümdeki ilk satır için 1'den başlayarak, sonuç kümesinin bir bölümündeki bir satırın sıralı sayısını döndürür.

Aşağıdaki örnek, SiparişTarihi sırasına göre 50 ila 60 arası sayılar içeren satırları döndürür.

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

15

Http://www.codeproject.com/KB/aspnet/PagingLarge.aspx adresinde farklı sayfalama tekniklerine iyi bir genel bakış vardır.

ROWCOUNT yöntemini çoğunlukla SQL Server 2000 ile kullandım (2005 ve 2008 ile de çalışacak, sadece ROW_NUMBER ile karşılaştırıldığında performansı ölçecek), yıldırım hızında, ancak sıralanan sütunların (çoğunlukla) ) benzersiz değerler.


1
İlginçtir ki, bu makale sabit zamanda çağrı yapabilen arama yönteminden bahsetmez ... Yine de iyi bir makale
Lukas Eder

6

SQL Server 2000 için bir IDENTITY sütunu olan bir tablo değişkeni kullanarak ROW_NUMBER () benzetimini yapabilirsiniz:

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

Bu yaklaşım, çok sütunlu tuşlara sahip tablolara genişletilebilir ve OR (performans kullanımını atlar) kullanmanın performans yükünü etkilemez. Dezavantajı, veri kümesi çok büyük ve biri son sayfanın yakınındaysa kullanılan geçici alan miktarıdır. Bu durumda imleç performansını test etmedim, ancak daha iyi olabilir.

Bu yaklaşımın verilerin ilk sayfası için optimize edilebileceğini unutmayın. Ayrıca TOP SQL Server 2000'de bir değişkeni kabul etmediğinden ROWCOUNT kullanıldı.


3

Sql server 2012 sayfalama için en iyi yolu bir saklı yordamda ofset ve getir sonraki kullanmaktır. OFSET Anahtar Kelime - offset yan tümcesiyle birlikte ofset kullanırsak, sorgu OFFSET n Satırda belirttiğimiz kayıt sayısını atlayacaktır.

FETCH NEXT Anahtar Kelimeler - Sonraki Getirme yan tümcesiyle bir siparişi kullandığımızda, sayfalamada görüntülemek istediğiniz satırların sayısını döndürür, Ofset olmadan SQL bir hata oluşturur. Aşağıda verilen örnek.

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

aşağıdaki gibi çalıştırabilirsiniz.

exec sp_paging 2,3

2

Bunlar SQL Server tarafında sorgu sonucu disk belleği için benim çözümler. bu yaklaşımlar SQL Server 2008 ve 2012 arasında farklıdır. Ayrıca, filtreleme ve sipariş kavramını tek bir sütunla ekledim. Gridview'da disk belleği ve filtreleme ve sipariş verirken çok etkilidir.

Test etmeden önce, bir örnek tablo oluşturmanız ve bu tabloya bir satır eklemeniz gerekir: (Gerçek dünyada tablo alanlarınızı göz önünde bulundurarak Where yan tümcesini değiştirmeniz gerekir ve belki de seçimin ana bölümünde birleştirme ve alt sorguya sahip olursunuz)

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

Tüm bu örnekte, sayfa başına 200 satır sorgulamak istiyorum ve 1200 numaralı sayfa için satır getiriyorum.

SQL Server 2008'de CTE konseptini kullanabilirsiniz. Bu nedenle, SQL Server 2008+ için iki tür sorgu yazdım

- 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

SQL Server 2008 ve sonrasında CTE ile ikinci çözüm

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;

1

Bu yaklaşımı deneyin:

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

1

Akıllıca kullanın, aşağıdakilerin kullanımı kolay ve hızlı görünmektedir. Sadece sayfa numarasını ayarlamanız yeterli.

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)

CTE olmadan da

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)

1
Nerede 1 = 1 ne yapar efendim?
Errol Paleracio

0

Peki SQL 2000 veritabanımda aşağıdaki örnek sorgu kullandık, SQL 2005 için de iyi çalışıyor. Verdiği güç, birden çok sütun kullanarak dinamik olarak sıralanır. Sana söylüyorum ... bu güçlü :)

    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

En iyi bölüm sp_executesql, aynı parametreleri iletmeniz koşuluyla daha sonraki çağrıları önbelleğe alır.


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

farklı init_id söz konusu olduğunda idx'i yeniden başlatacak


0

Teknik için, ROW_NUMBERkullanılacak bir sıralama sütununuz yoksa, CURRENT_TIMESTAMPaşağıdaki gibi kullanabilirsiniz :

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

Bu, 700.000'e kadar masa boyutlarında arama yapmak için benim için iyi çalıştı.

Bu, 11 ila 30 arasındaki kayıtları getirir.


İyi bir uygulama olarak, sayfalama ile, sonuç kümesinde benzersiz bir sütun kümesiyle sipariş vermeye çalışmalısınız, çünkü sipariş garantili olarak düşünülmemelidir.
Arin Taylor

2
Bu, 11 ila 30 arasındaki kayıtları getirir.
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

0

Bu bit, SQL Server'ı ve daha yeni MySQL sürümlerini kullanarak sayfalama yapabilmenizi sağlar ve her satırdaki toplam satır sayısını taşır. Benzersiz satır sayısını saymak için pimary anahtarınızı kullanır.

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

Kodunuzun ne yaptığını açıklayan herhangi bir yorum bırakabilir misiniz?
Doug F


0

2012'den itibaren kullanabiliriz OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY


-19

Dili veya hangi sürücüyü kullandığınızı belirtmediniz. Bu yüzden soyut olarak tarif ediyorum.

  • Kaydırılabilir bir sonuç kümesi / veri kümesi oluşturun. Bu, tablo (lar) da birincil olmalıdır
  • sonuna kadar atla
  • satır sayısını istemek
  • sayfanın başına atla
  • sayfanın sonuna kadar satırlar arasında kaydırma
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.