SQL veritabanı tablosundaki n. Satırı nasıl seçerim?


399

Ben seçerek bazı (ideal) veritabanı agnostik yollarını öğrenme ilgilenen kulüpler n bir veritabanı tablosundan inci satır. Aşağıdaki veritabanlarının yerel işlevlerini kullanarak bunun nasıl başarılabileceğini görmek de ilginç olacaktır:

  • SQL Server
  • MySQL
  • PostgreSQL
  • SQLite
  • torpil

Şu anda SQL Server 2005'te aşağıdaki gibi bir şey yapıyorum, ancak başkalarının daha agnostik yaklaşımlarını görmek ilgimi çekiyor:

WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000

Yukarıdaki SQL için kredi: Firoz Ansari'nin Web Günlüğü

Güncelleme: Troels Arvin'in SQL standardıyla ilgili cevabına bakınız . Troels, alıntı yapabileceğimiz herhangi bir bağ var mı?


3
Evet. İşte ISO SQL standardı hakkındaki bilgilere bir link: troels.arvin.dk/db/rdbms/links/#standards
Troels Arvin

13
Bir ilişkinin tanımıyla, tablodaki satırların sıraya sahip olmadığını belirtmek için, tablodaki N. Satırın seçilemeyeceğini belirtmek gerekir. Seçilebilen, bir sorgunun (geri kalanının) döndürdüğü bir satır kümesindeki N'inci satırdır; bu, örneğin ve diğer tüm yanıtların gerçekleştirdiği şeydir. Çoğu için bu sadece semantik olabilir, ancak sorunun altında yatan soruna işaret eder. Karşılığında gereğini yaparsanız OrderNo N, o zaman bir tanıtmak OrderSequenceNo tablosundaki sütun ve bir onu üretmek bağımsız dizi üreteci yeni bir düzen yaratmak üzerine.
Damir Sudarevic

2
SQL standardı seçeneği tanımlar offset x fetch first y rows only. Şu anda (en azından) Postgres, Oracle12, DB2 tarafından desteklenmektedir.
a_horse_with_no_name

Yanıtlar:


349

Bunu standardın isteğe bağlı bölümlerinde yapmanın yolları vardır, ancak birçok veritabanı kendi yöntemlerini destekler.

Bu ve diğer şeylerden bahseden gerçekten iyi bir site http://troels.arvin.dk/db/rdbms/#select-limit .

Temel olarak, PostgreSQL ve MySQL standart olmayanları destekler:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 ve MSSQL standart pencereleme işlevlerini destekler:

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber <= n

(bu DB'leri asla kullanmadım çünkü yukarıda bağlı siteden kopyaladım)

Güncelleme: PostgreSQL 8.4'ten itibaren standart pencereleme fonksiyonları desteklenmektedir, bu nedenle ikinci örneğin PostgreSQL için de çalışmasını bekleyin.

Güncelleme: SQLite eklenen pencere işlevleri 2018-09-15'te 3.25.0 sürümünde desteklenir, böylece her iki form da SQLite'de çalışır.


3
MySQL, OFFSET ve LIMIT sözdizimini de kullanır. Firebird FIRST ve SKIP anahtar kelimeleri kullanır, ancak SELECT öğesinden hemen sonra yerleştirilir.
Doug

7
Bu WHERE rownumber = nsadece n. Sırayı almak değil mi?
Steve Bennett

MySQL, sürüm 8'den beri pencere işlevlerini destekliyor. 10.2'den beri MariaDB
Paul Spiegel

102

PostgreSQL , SQL standardı tarafından tanımlanan pencereleme işlevlerini destekler , ancak gariptir, bu nedenle çoğu kişi (standart dışı) LIMIT/ kullanırOFFSET :

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;

Bu örnek 21. satırı seçer. OFFSET 20Postgres'a ilk 20 kaydı atlamasını söylüyor. Bir ORDER BYcümle belirtmezseniz , hangi kaydı geri alacağınızın garantisi yoktur ve bu nadiren kullanışlıdır.


31

Geri kalanı hakkında emin değilim, ama SQLite ve MySQL herhangi bir "varsayılan" satır sırası yok biliyorum. Bu iki lehçede, en azından aşağıdaki snippet, eklendiği tarihe / saate göre sıralayarak the_table'ın 15. girişini alır:

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15

(elbette, bir DATETIME alanı eklemeniz ve bu girdinin eklendiği tarih / saate ayarlamanız gerekir ...)


Bu, sorguyu satır içi ofset değeriyle sınırlamanın en iyi yolu gibi görünüyor. Ama burada 0,14 kullanmamalıyız? 1,15 ilk sırayı terk edecek.
Gladyatör

15 ne anlama geliyor? Biliyorum ki 1 bir kayıt olsun diyor. Virgül, 1keydata.com/sql/sql-limit.html
committedandroider

1
Aslında buradan php.about.com/od/mysqlcommands/g/Limit_sql.htm sen kapmak istiyorsa, 15 giriş, SINIR 14, 1 (0 ilk unsur, uzunluğunun 1'dir yapmazdı
committedandroider

SEÇİLMELİDİR * the_table ORDER BY'DAN DESC LIMIT 15,1
JerryGoyal

25

SQL 2005 ve üstü bu özelliğe sahiptir. ROW_NUMBER () işlevini kullanın. << Önceki ve Sonraki >> tarzı tarama özelliğine sahip web sayfaları için mükemmeldir:

Sözdizimi:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

Bu çözümü tercih ediyorum, çünkü daha doğrudan hissediyor.
FoxArc

18

Bunun çılgınca verimsiz olduğunu, ancak denediğim küçük bir veri kümesinde çalışan oldukça basit bir yaklaşım olduğundan şüpheleniyorum.

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

Bu, 5. öğeyi alır, farklı bir n. Öğeyi elde etmek için ikinci üst numarayı değiştirir

Yalnızca SQL sunucusu (sanırım) ancak ROW_NUMBER () 'i desteklemeyen eski sürümlerde çalışmalıdır.


Bunu ROW_NUMBER () SQL 2000'de çalışmıyor gibi kullanacağım (evet, SQL 2000 üzerinde hala bir istemcimiz var) Özellikle, '5' i bir döngü yineleyici değişkeni ile değiştireceğim ve kullanacağım sırayla bir tablonun her satırını kopyalayıp değiştirmek. Belki birisi bu yorumu görüp faydalı bulacaktır
Inversus


14

SQL Server'da doğrulayın:

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp

Bu size emp tablo 10. ROW verecektir!


Burada zaten bu soruya bir cevap verdiniz. Doğru olmadığını düşündüğünüz cevabı silin. Her iki cevabın da doğru olduğunu düşünüyorsanız her iki yanıtı da tek bir yerde
yayınlayın

11

Bazı cevapların iddialarının aksine, SQL standardı bu konuda sessiz değildir.

SQL: 2003'ten bu yana, satırları atlamak ve sonuç kümelerini sınırlamak için "pencere işlevlerini" kullanabilirsiniz.

SQL: 2008'de, aşağıdakileri kullanarak biraz daha basit bir yaklaşım eklenmişti:
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

Şahsen, SQL: 2008'in eklenmesinin gerçekten gerekli olduğunu düşünmüyorum, bu yüzden ISO olsaydım, zaten oldukça büyük bir standarttan uzak tutmalıydım.


Bir standart olsa onun güzel, kendimi hayat gibi insanlar kolaylaştırır ve standart bir şekilde şeyler yapmak için microsoft çok güzel yapar :)
user230910 15:08

7

MSSQL 2000'de çalıştığımızda, "üçlü flip" dediğimiz şeyi yaptık:

REDAKTE

DECLARE @InnerPageSize int
DECLARE @OuterPageSize int
DECLARE @Count int

SELECT @Count = COUNT(<column>) FROM <TABLE>
SET @InnerPageSize = @PageNum * @PageSize
SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize)

IF (@OuterPageSize < 0)
    SET @OuterPageSize = 0
ELSE IF (@OuterPageSize > @PageSize)
    SET @OuterPageSize = @PageSize

DECLARE @sql NVARCHAR(8000)

SET @sql = 'SELECT * FROM
(
    SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM
    (
        SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC
    ) AS t1 ORDER BY <column> DESC
) AS t2 ORDER BY <column> ASC'

PRINT @sql
EXECUTE sp_executesql @sql

Zarif değildi ve hızlı değildi, ama işe yaradı.


25 satırınız olduğunu ve 10 satır sayfa boyutunun üçüncü sayfasını istediğinizi, yani 21-25 satırlarını istediğinizi varsayalım. En içteki sorgu ilk 30 satırı alır (satır 1-25). Orta sorgu son 10 satırı alır (satır 25-16). Dış sorgu onları yeniden sıralar ve 16-25. Satırları döndürür. 21-25 satırları istiyorsanız bu açıkça yanlıştır.
Bill Karwin

Şimdi orta sayfa istiyorsak çalışmıyor. Diyelim ki 25 satırımız var ve ikinci sayfayı istiyoruz, yani 11-20 satırları. İç sorgu en iyi 2 * 10 = 20 satırı veya 1-20 satırı alır. Orta sorgu son 15 satırı alır: 25 - ((2-1) * 10) = 15, bu satır 20-6 verir. Son sorgu, sırası tersine çevirir ve 6-20 arasındaki satırları döndürür. Toplam satır sayısı istediğiniz sayfa boyutunun katı olmadığı sürece bu teknik çalışmaz.
Bill Karwin

Belki de en iyi sonuç, kalan MS SQL Server 2000 örneklerini yükseltmemiz gerektiğidir. :-) Neredeyse 2012 ve bu sorun yıllardır daha iyi şekillerde çözüldü!
Bill Karwin

@Bill Karwin: Hesaplamanın IF / ELSE IFaltındaki bloklara dikkat edin OuterPageSize- sayfa 1 ve 2'de OuterPageSizedeğeri 10'a düşürürler . Sayfa 3'te (satır 21-25) hesaplama 5'i ve tüm sayfa 4 ve daha büyüklerinde, hesaplamadaki negatif sonuç 0 ile değiştirilir (ancak bu noktada boş bir veri satırını hemen döndürmek daha hızlı olacaktır).
Adam V

Şimdi anlıyorum. Bence, bugün MS SQL Server 2000 kullanmanın zahmete değmeyeceğini düşünüyorum.
Bill Karwin

6

SQL SERVER


En üstteki n. Kaydı seç

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

alttan n kaydı seç

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

5

Oracle:

select * from (select foo from bar order by foo) where ROWNUM = x

1
where ROWNUM = xOracle DB'de yalnızca x = 1 için çalışır. yani where ROWNUM = 2herhangi bir satır döndürmez.
aff

5

Oracle 12c olarak, sen kullanabilir OFFSET..FETCH..ROWS ile seçeneğiORDER BY

Örneğin, 3. kaydı üstten almak için:

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;

4

İşte karışıklığınızın hızlı bir çözümü.

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

Burada N = 0 Doldurarak Son satırı, N = 1 Doldurarak Son satırı, N = 3 Doldurarak Dördüncü Sonu alabilirsiniz.

Bu röportajda çok yaygın bir soru ve bu çok basit ve çok basit.

Daha fazla İsterseniz, Miktar, Kimlik veya u'dan daha bazı Sayısal Sıralama Düzeni MySQL'de CAST işlevi için gidebilir.

SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1

Burada N = 4'ü doldurarak CART tablosundan Beşinci En Son Tutar Kaydını alabilirsiniz. Alanınızı ve tablo adınızı sığdırabilir ve çözüm bulabilirsiniz.



3

Örneğin, MSSQL'deki her 10. satırı seçmek istiyorsanız, şunu kullanabilirsiniz;

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
  FROM TableName
) AS foo
WHERE rownumber % 10 = 0

MOD'u alın ve burada istediğiniz 10 numarayı değiştirin.


3

SQL Server için, satır numarasına gitmenin genel bir yolu şöyledir:

SET ROWCOUNT @row --@row = the row number you wish to work on.

Örneğin:

set rowcount 20   --sets row to 20th row

select meat, cheese from dbo.sandwich --select columns from table at 20th row

set rowcount 0   --sets rowcount back to all rows

Bu, 20. satırın bilgisini döndürür. Daha sonra 0 satır sayısını eklediğinizden emin olun.


2

LIMIT n, 1, MS SQL Server'da çalışmaz. Bu sözdizimini desteklemeyen tek büyük veritabanı olduğunu düşünüyorum. Adil olmak gerekirse, SQL standardının bir parçası değildir, ancak olması gerektiği kadar geniş bir şekilde desteklenmektedir. SQL Server dışında her şey LIMIT harika çalışıyor. SQL sunucusu için zarif bir çözüm bulamadım.


1
Oracle hariç, DB2, tüm dünyadaki hemen hemen her kurumsal düzey veritabanı. PostgreSQL, LIMIT anahtar sözcüğünü destekleyen tek kurumsal yetenekli veritabanı ile ilgilidir ve bunun nedeni çoğunlukla açık kaynak olması nedeniyle ACID görmezden gelen MySQL kalabalığı tarafından ulaşılabilir olmasıdır.
David

3
@AlexD Bu "yanıt", yorumlar uygulanmadan önce Stackoverflow'un eski günlerinde geri gönderildi. Bunu başka bir cevaba yorum olarak gönderirdim, ama zaman zaman yorumlar yoktu.
Kibbee

2

İşte Oracle için yakın zamanda yazdığım ve dinamik sayfalamaya / sıralamaya izin veren bir sproc'un genel bir sürümü - HTH

-- p_LowerBound = first row # in the returned set; if second page of 10 rows,
--                this would be 11 (-1 for unbounded/not set)
-- p_UpperBound = last row # in the returned set; if second page of 10 rows,
--                this would be 20 (-1 for unbounded/not set)

OPEN o_Cursor FOR
SELECT * FROM (
SELECT
    Column1,
    Column2
    rownum AS rn
FROM
(
    SELECT
        tbl.Column1,
        tbl.column2
    FROM MyTable tbl
    WHERE
        tbl.Column1 = p_PKParam OR
        tbl.Column1 = -1
    ORDER BY
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC,
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC
))
WHERE
    (rn >= p_lowerBound OR p_lowerBound = -1) AND
    (rn <= p_upperBound OR p_upperBound = -1);

2

Ama gerçekten, tüm bunlar aslında sadece iyi bir veritabanı tasarımı için salon numaralarını değil mi? Birkaç kez hızlı bir rapor yapmak için basit bir kapalı sorgu için böyle bir işlevsellik gerekiyordu. Herhangi bir gerçek iş için, bunun gibi numaralar kullanmak sorun çıkarır. Belirli bir satır seçmek gerekirse, sıralı değere sahip bir sütun olması ve onunla yapılması yeterlidir.


2

SQL sunucusu için aşağıdakiler tablodan ilk satırı döndürür.

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

Değerler arasında şunun gibi bir şeyle döngü yapabilirsiniz:

WHILE @constVar > 0
BEGIN
    declare @rowNumber int = @consVar;
       select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
       select TOP(@rowNumber - 1) * from [dbo].[someTable];  

       SET @constVar = @constVar - 1;    
END;

1

Her Yerde Sybase SQL'de:

SELECT TOP 1 START AT n * from table ORDER BY whatever

SİPARİŞ TARAFINDAN unutmayın ya da anlamsız.


1

T-SQL - Tablodan N. RecordNumber seçme

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber

Where  RecordNumber --> Record Number to Select
       TableName --> To be Replaced with your Table Name

Örneğin, bir Tablo Çalışanı'ndan 5. kaydı seçmek için, sorgunuz

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5

1
SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);

1
SELECT
    top 1 *
FROM
    table_name
WHERE
    column_name IN (
        SELECT
            top N column_name
        FROM
            TABLE
        ORDER BY
            column_name
    )
ORDER BY
    column_name DESC

Nth satır bulmak için bu sorguyu yazdım. Bu sorguyu içeren örnek

SELECT
    top 1 *
FROM
    Employee
WHERE
    emp_id IN (
        SELECT
            top 7 emp_id
        FROM
            Employee
        ORDER BY
            emp_id
    )
ORDER BY
    emp_id DESC

0

inanılmaz bir bunu yürüten bir SQL motoru bulabilirsiniz ...

WITH sentence AS
(SELECT 
    stuff,
    row = ROW_NUMBER() OVER (ORDER BY Id)
FROM 
    SentenceType
    )
SELECT
    sen.stuff
FROM sentence sen
WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1

0

Hiçbir şey fantezi, özel fonksiyon yok, Caché'yi benim yaptığım gibi kullanmanız durumunda ...

SELECT TOP 1 * FROM (
  SELECT TOP n * FROM <table>
  ORDER BY ID Desc
)
ORDER BY ID ASC

Güvenebileceğiniz bir kimlik sütununuz veya bir tarih damgası sütununuz olduğu göz önüne alındığında.


0

Bu DB2 SQL içinde nasıl yaparım, RRN (göreli kayıt numarası) O / S tarafından tablo içinde saklanır inanıyorum;

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber

0
select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

İlk önce artan sırada sipariş ederek ilk 100 satırı seçin, ardından azalan ve 1 ile sınırlayarak son satırı seçin. Ancak bu, verilere iki kez eriştiği için çok pahalı bir ifadedir.


0

Bana öyle geliyor ki, verimli olmak için, 1) 0 ile bir arasında veritabanı kaydı sayısından daha az rastgele bir sayı üretmeniz ve 2) bu konumdaki satırı seçebilmeniz gerekir. Ne yazık ki, farklı veritabanları farklı rasgele sayı üreteçlerine ve sonuç kümesindeki bir konumda bir satır seçmenin farklı yollarına sahiptir - genellikle kaç satır atlayacağınızı ve kaç satır istediğinizi belirtirsiniz, ancak farklı veritabanları için farklı yapılır. İşte SQLite benim için çalışan bir şey:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Sınır yan tümcesinde bir alt sorgu kullanabilmenize bağlıdır (SQLite'de LIMIT <atlamak için recs>, <almak için recs>) Tablodaki kayıt sayısını seçmek, veritabanının bir parçası olmak üzere özellikle verimli olmalıdır meta veri, ancak bu veritabanı uygulamasına bağlıdır. Ayrıca, sorgu aslında Nth kaydını almadan önce sonuç kümesi inşa edeceğini bilmiyorum, ama bunu gerekmez umuyoruz. Bir "sipariş ölçütü" maddesi belirtmediğimi unutmayın. Bir dizine sahip birincil anahtar gibi bir şeyle "sipariş vermek" daha iyi olabilir - sonuç kümesini oluşturmadan veritabanı veritabanından Nth kaydını alamazsa, bir dizinden Nth kaydı almak daha hızlı olabilir .


0

Sql server için bu makalede gördüğüm en uygun cevap

WITH myTableWithRows AS (
    SELECT (ROW_NUMBER() OVER (ORDER BY myTable.SomeField)) as row,*
    FROM myTable)
SELECT * FROM myTableWithRows WHERE row = 3
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.