SQL Server'da Satır Uzaklığı


133

SQL Server'da sonuçları belirli bir uzaklıktan başlayarak almanın bir yolu var mı? Örneğin, başka bir SQL veritabanı türünde şunları yapmak mümkündür:

SELECT * FROM MyTable OFFSET 50 LIMIT 25

51-75 sonuç almak için. Bu yapı SQL Server'da görünmüyor.

Umursamadığım tüm satırları yüklemeden bunu nasıl başarabilirim? Teşekkürler!


Göreli konum kullanabilir ve sonraki ifadeyi getirebilirsiniz. youtu.be/EqHkAiiBwPc
Amresh Kumar Singh

Yanıtlar:


152

Kullanmaktan kaçınırım SELECT *. Hepsi olsa bile, gerçekten istediğiniz sütunları belirtin.

SQL Server 2005+

SELECT col1, col2 
FROM (
    SELECT col1, col2, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
    FROM MyTable
) AS MyDerivedTable
WHERE MyDerivedTable.RowNum BETWEEN @startRow AND @endRow

SQL Server 2000

SQL Server 2000'de Büyük Sonuç Kümeleri Üzerinden Etkin Bir Şekilde Sayfalama

Büyük Sonuç Kümeleri Üzerinden Sayfalandırmak İçin Daha Etkili Bir Yöntem


6
Neden tüm sütunları seçseniz bile SEÇİM'den kaçınmanızı öneriyorsunuz?
Adam Ness

12
Eminim "*" kullanmıştır çünkü yazmak daha kolaydı ve noktayı "col1, col2, ... colN" den daha iyi anlamıştı
gillonba

9
Neden kullanılmayacağına gelince, SELECT *tablonun yapısı değişirse, sorgunuzun hala çalıştığı, ancak farklı sonuçlar verdiği anlamına gelir. Bir sütun eklenirse, bu yararlı olabilir (yine de bir yerde adıyla kullanmanız gerekse de); bir sütun silinir veya yeniden adlandırılırsa, SQL'inizin görünür bir şekilde kırılması, kodun daha aşağıya doğru tuhaf davranmasından daha iyidir, çünkü bir değişken başlatılmamıştır.
IMSoP

5
tablonun tüm verilerini seç ve kes? 5000000000 satırınız varsa? 5000000000 satır seçin ve her sorgu için kesin. sunucunun cpu ve hafızası için verimli değildir.
e-info128

3
Lütfen 2012+ sürümünün daha iyi uyguladığını unutmayın. + Martin Smith tarafından verilen yanıta bakın
meridius

100

Tüm sayfaları sırayla işleyecekseniz, önceki sayfada görülen son anahtar değerini hatırlamak ve TOP (25) ... WHERE Key > @last_key ORDER BY Keybunun verimli bir şekilde aranmasını sağlamak için uygun dizinler varsa en iyi performans gösteren yöntem veya yoksa bir API imleci kullanmak olabilir. .

Rasgele bir sayfa seçmek için SQL Server 2005 - 2008 R2 için en iyi çözüm muhtemelen ROW_NUMBERveBETWEEN

SQL Server 2012+ için bu ihtiyaç için geliştirilmiş ORDER BY deyimini kullanabilirsiniz .

SELECT  *
FROM     MyTable 
ORDER BY OrderingColumn ASC 
OFFSET  50 ROWS 
FETCH NEXT 25 ROWS ONLY 

Gerçi o göreceğiz performans bu seçenek ne kadar iyi olacaktır .


2
Artık SQL Server Compact 4.0'da mevcuttur -> msdn.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
Bart Verkoeijen

13
Bunu tSQL'e eklemelerinin zamanı geldi
JohnFx

3
Sadece Sql Server 2012 için :(
e-info128

22

Bu tek yol (SQL2000)

SELECT * FROM
(
    SELECT TOP (@pageSize) * FROM
    (
        SELECT TOP (@pageNumber * @pageSize) *
        FROM tableName 
        ORDER BY columnName ASC
    ) AS t1 
    ORDER BY columnName DESC
) AS t2 
ORDER BY columnName ASC

ve bu başka bir yoldur (SQL 2005)

;WITH results AS (
    SELECT 
        rowNo = ROW_NUMBER() OVER( ORDER BY columnName ASC )
        , *
    FROM tableName 
) 
SELECT * 
FROM results
WHERE rowNo between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize

Birincisini açıklığa kavuşturmak için ... (@pageSize) burada gerçek değer için bir yer tutucudur. Özellikle 'İLK 25'i yapmanız gerekecek; SQL Server 2000, bir TOP yan tümcesinde değişkenleri desteklemez. Bu, dinamik SQL'i içeren bir acıya dönüşür.
Cowan

5
SQL2000 için bu çözüm, toplam satır sayısı sayfa boyutunun katı olmadığı sürece sonuç kümesindeki son sayfa için çalışmaz.
Bill Karwin

10

İstediğinizi elde etmek için ROW_NUMBER()işlevi kullanabilirsiniz :

SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t
WHERE RowNr BETWEEN 10 AND 20

7

Orada OFFSET .. FETCHSQL Server 2012'de, ancak bir belirtmeniz gerekir ORDER BYsütun.

Bir sütun olarak geçirebileceğiniz açık bir sütununuz yoksa ORDER BY(diğerlerinin önerdiği gibi), o zaman şu numarayı kullanabilirsiniz:

SELECT * FROM MyTable 
ORDER BY @@VERSION 
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

... veya

SELECT * FROM MyTable 
ORDER BY (SELECT 0)
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

Kullanıcılar açıkça bir sipariş belirtmediğinde bunu jOOQ'da kullanıyoruz . Bu, daha sonra herhangi bir ek maliyet olmadan oldukça rastgele sipariş üretecektir.


6

Daha fazla ve büyük veri sütunlarına sahip tablolar için şunları tercih ederim:

SELECT 
  tablename.col1,
  tablename.col2,
  tablename.col3,
  ...
FROM
(
  (
    SELECT
      col1
    FROM 
    (
      SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum
      FROM tablename
      WHERE ([CONDITION])
    )
    AS T1 WHERE T1.RowNum BETWEEN [OFFSET] AND [OFFSET + LIMIT]
  )
  AS T2 INNER JOIN tablename ON T2.col1=tablename.col1
);

-

[CONDITION] can contain any WHERE clause for searching.
[OFFSET] specifies the start,
[LIMIT] the maximum results.

BLOB'lar gibi büyük verilere sahip tablolarda çok daha iyi performansa sahiptir, çünkü ROW_NUMBER işlevi yalnızca bir sütuna bakmalıdır ve tüm sütunlarla birlikte yalnızca eşleşen satırlar döndürülür.


5

Sayfalayıcı seçimime bakın

SELECT TOP @limit * FROM (
   SELECT ROW_NUMBER() OVER (ORDER BY colunx ASC) offset, * FROM (

     -- YOU SELECT HERE
     SELECT * FROM mytable


   ) myquery
) paginator
WHERE offset > @offset

Bu, sayfalandırmayı çözer;)


3
SELECT TOP 75 * FROM MyTable
EXCEPT 
SELECT TOP 50 * FROM MyTable

Sorgu daha sonra gereksiz yere iki kez yürütüldüğünden performans açısından optimal görünmüyor. Özellikle kullanıcı daha yüksek sayfalara gittiğinde, satırları silme sorgusu, yani aşağıdaki EXCEPT daha uzun sürecektir.
vanval

2

Sürümünüze bağlı olarak, bunu doğrudan yapamazsınız, ancak

select top 25 *
from ( 
  select top 75 *
  from   table 
  order by field asc
) a 
order by field desc 

burada anahtar "alan" dır.


4
SQL2000 için bu çözüm, toplam satır sayısı sayfa boyutunun katı olmadığı sürece sonuç kümesindeki son sayfa için çalışmaz.
Bill Karwin

2

Aşağıda, SQL Server 2012'deki ilk 50 kayıt çalışması hariç 25 kayıt gösterilecektir.

SELECT * FROM MyTable ORDER BY ID OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY;

kimliğinizi gereği olarak değiştirebilirsiniz


Pls ayrıca, SQL SERVER 2012'de bunun mümkün olduğunu ekleyin
Usman Younas

2

ROW_NUMBER() OVER (ORDER BY)Performans oldukça zayıf olduğu için ifadeyi kullanırken dikkatli olmalısınız . Aynı şey Ortak Tablo İfadelerini kullanmak için ROW_NUMBER()de geçerli, daha da kötüsü. Sayfa numarasını sağlamak için kimliğe sahip bir tablo değişkeni kullanmaktan biraz daha hızlı olduğu kanıtlanmış aşağıdaki parçacığı kullanıyorum.

DECLARE @Offset INT = 120000
DECLARE @Limit INT = 10

DECLARE @ROWCOUNT INT = @Offset+@Limit
SET ROWCOUNT @ROWCOUNT

SELECT * FROM MyTable INTO #ResultSet
WHERE MyTable.Type = 1

SELECT * FROM
(
    SELECT *, ROW_NUMBER() OVER(ORDER BY SortConst ASC) As RowNumber FROM
    (
        SELECT *, 1 As SortConst FROM #ResultSet
    ) AS ResultSet
) AS Page
WHERE RowNumber BETWEEN @Offset AND @ROWCOUNT

DROP TABLE #ResultSet

Bu, 10 satır yerine 11 satır döndürecektir.
Aaron Bertrand

1

Bu tekniği sayfalandırma için kullanıyorum. Tüm satırları getirmiyorum. Örneğin, sayfamın ilk 100 satırı görüntülemesi gerekiyorsa, sadece where cümlesiyle birlikte 100'ü getiriyorum. SQL çıktısının benzersiz bir anahtarı olmalıdır.

Tabloda şunlar bulunur:

ID, KeyId, Rank

Aynı sıra, birden fazla KeyId için atanacaktır.

SQL select top 2 * from Table1 where Rank >= @Rank and ID > @Id

İlk defa her ikisi için de 0'ı geçtim. İkinci kez 1 ve 14'ü geçer. 3. kez 2 ve 6'yı geçer ...

10. rekor Rank & Id'nin değeri bir sonrakine aktarılır

11  21  1
14  22  1
7   11  1
6   19  2
12  31  2
13  18  2

Bu, sistem üzerinde en az strese sahip olacak


1

SqlServer2005'te şunları yapabilirsiniz:

DECLARE @Limit INT
DECLARE @Offset INT
SET @Offset = 120000
SET @Limit = 10

SELECT 
    * 
FROM
(
   SELECT 
       row_number() 
   OVER 
      (ORDER BY column) AS rownum, column2, column3, .... columnX
   FROM   
     table
) AS A
WHERE 
 A.rownum BETWEEN (@Offset) AND (@Offset + @Limit-1) 

Olması gerekmiyor @Offset + @Limit - 1mu? @Limit 10 ise bu 11 satır döndürür.
Aaron Bertrand

1

Kayıtları sipariş etmek için zaman kaybetmeden yapmanın en iyi yolu şudur:

select 0 as tmp,Column1 from Table1 Order by tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY

bir saniyeden az sürer!
büyük masalar için en iyi çözüm.


0

Bir süredir bu cevabı arıyordum (genel sorgular için) ve bunu SQL Server 2000+ üzerinde ROWCOUNT ve imleçler kullanarak ve TOP veya herhangi bir geçici tablo olmadan yapmanın başka bir yolunu buldum.

Kullanarak SET ROWCOUNT [OFFSET+LIMIT]sonuçları sınırlandırabilir ve imleçlerle doğrudan istediğiniz satıra gidin, ardından sonuna kadar döngü yapın.

Yani sorgunuz şöyle olacaktır:

SET ROWCOUNT 75 -- (50 + 25)
DECLARE MyCursor SCROLL CURSOR FOR SELECT * FROM pessoas
OPEN MyCursor
FETCH ABSOLUTE 50 FROM MyCursor -- OFFSET
WHILE @@FETCH_STATUS = 0 BEGIN
    FETCH next FROM MyCursor
END
CLOSE MyCursor
DEALLOCATE MyCursor
SET ROWCOUNT 0

Masanın sonuna geldiğinizde bunun performansını görmekten nefret ediyorum ...
Aaron Bertrand

0

SQL Server 2012 (11.x) ve sonrası ve Azure SQL Veritabanı ile "fetch_row_count_expression" da olabilir, bununla birlikte ORDER BY cümlesine de sahip olabilirsiniz.

USE AdventureWorks2012;  
GO  
-- Specifying variables for OFFSET and FETCH values    
DECLARE @skip int = 0  , @take int = 8;  
SELECT DepartmentID, Name, GroupName  
FROM HumanResources.Department  
ORDER BY DepartmentID ASC   
    OFFSET @skip ROWS   
    FETCH NEXT @take ROWS ONLY; 

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

Note OFFSET Sorgu ifadesinden satır döndürmeye başlamadan önce atlanacak satır sayısını belirtir . Başlangıç ​​satır numarası DEĞİLDİR. Bu nedenle, ilk kaydı dahil etmek için 0 olması gerekir.

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.