SQL Server'da LIMIT 10..20


161

Gibi bir şey yapmaya çalışıyorum:

SELECT * FROM table LIMIT 10,20

veya

SELECT * FROM table LIMIT 10 OFFSET 10

ancak SQL Server kullanıyor

Bulduğum tek çözüm aşırıya kaçmış gibi görünüyor:

SELECT * FROM ( 
  SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases 
 ) a WHERE row > 5 and row <= 10

Ayrıca buldum :

SELECT TOP 10 * FROM stuff; 

... ancak başlangıç ​​sınırını belirleyemediğim için yapmak istediğim şey bu değil.

Bunu yapmamın başka bir yolu var mı?

Ayrıca, sadece merak ediyorum, SQL Server'ın LIMITişlevi veya benzer bir şeyi desteklememesinin bir nedeni var mı? Kötü olmak istemiyorum, ama bu gerçekten DBMS'nin ihtiyaç duyduğu bir şey gibi geliyor ... Eğer öyleyse, o kadar cahil olduğum için üzgünüm! MySQL ve SQL + ile son 5 yıldır çalışıyorum ...


1
Aralığın genişliği için bir CTE kullanmak ROW_NUMBER()ve bununla sınırlamak TOPve aralığın WHEREbir sınırı için bir koşul elde edebilmek en iyisidir. Ayrıca, TOPmadde değişken yerine değişmez bir bilgi kullanıyorsa , çok daha iyi bir performans fark ettim
Jodrell

ROW_NUMBER () ile ilgili herhangi bir çözümle ilgili sorun, önceden hangi sütunlara sahip olacağınızı bilmiyorsanız ve birleştirmelerinizin olması ve birleştirilen tabloların aynı sütun adına sahip olması durumunda, "Sütun "xxx" birden çok kez belirtildi ". Bu başlangıçta göründüğü kadar nadir değildir. Dapper kullanıyorum ve tablolarımın bir Id sütunu var. Dapper böler ve haritalar, bu yüzden onları yeniden adlandırmak istemiyorum, ama SELECT * FROM ([orijinal sorgu]) takma ad kullanamazsınız. Henüz bir çözüm bulamadım!
Steve Owen

Yanıtlar:


104

LIMITFıkra standart SQL bir parçası değildir. MySQL, PostgreSQL ve SQLite tarafından SQL için bir tedarikçi uzantısı olarak desteklenir.

Diğer veritabanı markaları benzer özelliklere sahip olabilir (ör. TOP Microsoft SQL Server'da), ancak bunlar her zaman aynı şekilde çalışmaz.

Kullanımı zor TOPMaddeyi taklit etmek için Microsoft SQL Server'daLIMIT . Sadece işe yaramadığı durumlar var.

Gösterdiğiniz çözüm, ROW_NUMBER() , Microsoft SQL Server 2005 ve sonraki sürümlerde kullanılabilir. Bu, yalnızca sorgunun bir parçası olarak çalışan en iyi çözümdür (şimdilik).

Başka bir çözüm, TOPilk sayım + ofset satırlarını getirmek ve daha sonra ilk sayıyı geçmek için API'yı kullanmaktır. ofset satırlarını .

Ayrıca bakınız:


135

SQL Server 2012 + için kullanabilirsiniz .

SELECT  *
FROM     sys.databases
ORDER BY name 
OFFSET  5 ROWS 
FETCH NEXT 5 ROWS ONLY 

10
SQl Server 2012 YALNIZCA OFSET 5 SIRALI FETCH SONRAKİ 5 SIRA kullandığınızda SİPARİŞ belirtmenizi gerektirirken, LIMIT 5,5
Tomas Kubes

4
@ qub1n - MySQL , bu durumda hangi satırları geri alacağınızı garanti etmez .
Martin Smith

3
Kullanmak offsetzorunda mısınız yoksa bu çizgiyi bırakabiliyor musunuz (ofset istemediğinizi varsayarak)?
Cullub


Örnek sorgu iyi çalışır, ancak tablo adını ve sırasını aşağıdaki gibi col olarak değiştirirsem SELECT * FROM DimProduct ORDER BY ProductKey OFSET 5 ROWS FETCH NEXT 5 SADECE SADECE Hata verirParse error at line: 4, column: 1: Incorrect syntax near 'OFFSET'
shashwat

36

Bulduğunuz gibi, bu tercih edilen sql sunucu yöntemidir:

SELECT * FROM ( 
  SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases 
 ) a WHERE a.row > 5 and a.row <= 10

Neden aiç seçimden sonra? İç seçime bir takma ad verdiğinizi varsayalım, ama o zaman bunu asla kullanmıyorsunuz ... O zaman a.rowsadece yerine rowmi yapmalısınız ?
Lucas

3
@Lucas, ( )türetilmiş tablodan sonra bir takma ad koymanız gerekir , ancak daha sonra sütunlara başvurmak için kullanmayı unutursanız gitmesine izin verir. Yine de düzelttim ...
KM.

teşekkürler, zor yoldan öğrendim (takma adı dışarıda bırakmaya çalıştım).
Lucas

1
Oy verildi +1: Ancak, @MartinSmith'in cevabı daha fazla oy verildi, yürütme planını bu yaklaşımla karşılaştırdıktan sonra, bu çözümün daha hızlı çalıştığını öğrendim.
Sert

10

İçin SQL Server 2012+ oyu kullanıyorsanız Martin Smith'in cevap ve kullanımı OFFSETve FETCH NEXTuzantıları ORDER BY,

Önceki bir sürümle sıkışacak kadar talihsizseniz, böyle bir şey yapabilirsiniz,

WITH Rows AS
(
    SELECT
              ROW_NUMBER() OVER (ORDER BY [dbo].[SomeColumn]) [Row]
            , *
        FROM
              [dbo].[SomeTable]
)
SELECT TOP 10
          *
     FROM
         Rows
    WHERE Row > 10

İşlevsel olarak eşit olduğuna inanıyorum

SELECT * FROM SomeTable LIMIT 10 OFFSET 10 ORDER BY SomeColumn

ve MS SQL 2012'den önce TSQL'de yapmayı bildiğim en iyi performans şekli.


Çok fazla satır varsa, CTE yerine geçici tablo kullanarak daha iyi performans elde edebilirsiniz.


2012 öncesi bir çözüm sunarken Martin Smith'in cevabına (ve ona bağlantı) işaret ettiği için seçildi. Ayrıca geçici tablo tavsiyesi için doğru çünkü :)
fujiiface

7

Ne yazık ki, ROW_NUMBER()yapabileceğiniz en iyisi. Aslında daha doğrudur, çünkü a limitveya topyan tümcesinin sonuçları belirli bir düzene saygı duymadan gerçekten bir anlam ifade etmez. Ama yine de yapacak bir acı.

Güncelleme: Sql Server 2012 limit, OFFSET ve FETCH anahtar sözcükleriyle benzer bir özellik ekler . Bu standart LIMITolmayan bir MySql uzantısı olan ansi standart yaklaşımıdır .


@Joel: ROW_NUMBER () öğesinin neden ORDER BY içinden çıktıklarını sıralayamadığını açıklayabilir misiniz? Her zaman neden "AŞIRI (SİPARİŞ ADI)" zorunlu olduğunu merak ettim, ama sanırım bunun için iyi bir neden var. Ya da en azından bir sebep.
Tomalak

3
çünkü madde emri olmadan emir diye bir şey yoktur. Kayıtların sunucu tarafından kullanılabildiği her siparişi alırsınız ve bu , sorgu isteğinden sorgu isteğine değişebilir .
Joel Coehoorn

1
@marcgg: Microsoft'un LIMIT'i uygulamayı planladığını hiç göstermedim. Böyle bir plana sahip olsalar bile, kapalı kaynak satıcıları özellikleri önceden duyurma eğilimindedir. Kesinlikle yararlı bir özellik olurdu, ancak kodları göz önüne alındığında, ne kadar işin uygulanacağını bilmiyoruz.
Bill Karwin

3
Kendinizi ORDER BY yan tümcesinde tekrarlamak istemiyorsanız, özgün sütun kümesi yerine ROW_NUMBER () diğer adını kullanın.
Peter Radocchia

2
@Tomalak: SQL Server söz konusu olduğunda, ROW_NUMBER () değerini hesaplamak için kullanılan sıralama sonuç kümesinin sıralamasıyla tamamen ilgisizdir. Bu yüzden onları ayrı ayrı belirtmelisiniz.
LukeH

6

Buna ne dersin?

SET ROWCOUNT 10 

SELECT TOP 20 *
FROM sys.databases
ORDER BY database_id DESC

İlk 20 satırın son 10 satırını verir. Bir dezavantaj, siparişin tersine çevrilmesidir, ancak en azından hatırlanması kolaydır.


6
Tabloda sadece 14 satır varsa ne olur? LIMIT 10 OFFSET 10 tarafından döndürülen satırlarla aynı olmayan 14 ile 5 arasındaki satırları alırsınız (14 ila 11 arasındaki satırlar olmalıdır).
Bill Karwin

2
SELECT TOP 10 *
FROM TABLE
WHERE IDCOLUMN NOT IN (SELECT TOP 10 IDCOLUMN FROM TABLE)

Kayıtları 11-20 vermelidir. Muhtemelen daha fazla sayfa almak için artırılıyorsa çok verimli değil ve siparişten nasıl etkilenebileceğinden emin değilim. Bunu her iki WHERE deyiminde de belirtmek gerekebilir.


1

İyi bir yöntem bir prosedür oluşturmaktır:

create proc pagination (@startfrom int ,@endto int) as
SELECT * FROM ( 
  SELECT *, ROW_NUMBER() OVER (ORDER BY name desc) as row FROM sys.databases 
 ) a WHERE a.row > @startfrom and a.row <= @endto

tıpkı 0,2 sınırı gibi /////////////// sayfalandırmayı 0,4 yürüt


1

Çoğu veritabanı motorunda çalışan kayıt çözümü için en verimli olmayabilir:

Select Top (ReturnCount) *
From (
    Select Top (SkipCount + ReturnCount) *
    From SourceTable
    Order By ReverseSortCondition
) ReverseSorted
Order By SortCondition

Pelase notu: SkipCount ne olursa olsun, son sayfa yine de ReturnCount satırlarını içerecektir. Ancak bu birçok durumda iyi bir şey olabilir.


1

LIMIT eşdeğeri SET ROWCOUNT'dur, ancak genel sayfalama istiyorsanız, böyle bir sorgu yazmak daha iyidir:

;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

0
select * from (select id,name,ROW_NUMBER() OVER (ORDER BY id  asc) as row
from tableName1) tbl1
where tbl1.row>=10 and tbl1.row<=15

10 ile 15 arasındaki satırları yazdıracaktır.


0

Şimdiye kadar bu format benim için çalışıyor (en iyi performans değil):

SELECT TOP {desired amount of rows} * 
FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY {order columns} asc)__row__ FROM {table})tmp
WHERE __row__ > {offset row count}

Yan taraftaki dinamik veriler üzerinde sayfalama yapmak, garip / beklenmedik sonuçlara yol açabilir.


0

MS SQL Server çevrimiçi belgelerinden ( http://technet.microsoft.com/en-us/library/ms186734.aspx ), belirli bir satır kümesini almak için test ettiğim ve çalıştığım örnekler. ROW_NUMBER bir OVER gerektirir, ancak istediğiniz gibi sipariş verebilirsiniz:

WITH OrderedOrders AS
(
  SELECT SalesOrderID, OrderDate,
  ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
  FROM Sales.SalesOrderHeader 
) 
SELECT SalesOrderID, OrderDate, RowNumber  
FROM OrderedOrders 
WHERE RowNumber BETWEEN 50 AND 60;

0

Tüm SQL sunucularını kullanın:; tbl ile (SELI ROW_NUMBER () over ((1 seçin)) RowIndex olarak, * tablodan) olarak tbl ile RowIndex> = 10'u seçin.


-3
 SELECT * FROM users WHERE Id Between 15 and 25

MYSQl'deki gibi 15'den 25'e kadar yazdırır


2
Kullanıcı 15 ile 25 arasındaki bir kaydı silerse ne olur?
Gökçer Gökdal
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.