En alttaki satır nasıl seçilir?


100

SELECT TOP (200) yapabilirim ... ama neden BOTTOM (200) olmasın?

Felsefeye girmemek için demek istediğim, TOP (200) 'ün eşdeğerini nasıl yapabilirim ama tersine (aşağıdan, BOTTOM'un yapmasını beklediğiniz gibi ...)?

Yanıtlar:


89
SELECT
    columns
FROM
(
     SELECT TOP 200
          columns
     FROM
          My_Table
     ORDER BY
          a_column DESC
) SQ
ORDER BY
     a_column ASC

2
Neden türetilmiş bir tablo kullanıyorsunuz?
RichardOD

14
Satırları A-> Z sırasına göre döndürmek, ancak Z-> A sıralamasında ilk 200'ü seçmek istiyorsanız, bunu yapmanın bir yolu budur. Sadece SİPARİŞ TARAFININ değiştirilmesini öneren diğer yanıtlar, sıra dışı olacağından (OP'nin söylemediği sıra önemli olmadığı sürece) soruda açıklanan aynı sonuçları döndürmeyecektir.
Tom H

3
@Tom H. Ne demek istediğini birkaç saniye düşünmem gerekti (14 saattir ayaktayım). İlk başta cevaplarla seninki ile sıralama arasındaki farkı göremedim, ama şimdi anlayabiliyorum. Yani +1.
RichardOD

1
Daha küçük masalarda çalışırken bu ve diğer yanıtlar iyi sonuç verir. Sadece alttaki birkaç satırla ilgilendiğinizde tüm tabloyu bir sütuna göre sıralamanın değeceğini sanmıyorum.
steadyfish

1
iyi cevap, en iyi imho ... asıl sorun bunu bir ASP betiğinden yapamam, bu yüzden objRecordset'i manuel olarak veya ASP'nin sağladığı işlevle yeniden düzenlemem gerektiğini düşünüyorum ....
Andrea_86

98

Gereksizdir. Bir kullanabilir ORDER BYve DESCaynı etkiyi elde etmek için sıralamayı değiştirebilirsiniz .


3
google aynı şeyi söyledi ve şimdi 9 kişi katılıyorum, benim için yeterince iyi, teşekkürler: D
CloudMeta

9
DESC kullanmak son N satırı döndürür, ancak döndürülen satırlar da ilk N satırdan ters sırada olacaktır.
RickNZ

11
Tablonuzda ORDER BY endeks yoksa ne olur?
Protector one

8
@ Justin: Varchar değerlerini içeren tek bir sütuna sahip olduğunuzu düşünün. ORDER BY alfabetik olarak sıralar, ki bu (muhtemelen) istediğimiz şey değildir.
Koruyucu bir

3
Tom H. doğru cevaplayıcıdır, aksi takdirde satırlarınız ters sırada olacaktır.
Pierre-Olivier Goulet

39

Üzgünüm ama bence herhangi bir doğru cevap göremediğimi düşünüyorum.

TOPX yakalanan görünen tanımsız sırayla kayıtları çalışır. Bu tanımdan bir BOTTOMfonksiyonun tanımlanamayacağı anlaşılır .

Herhangi bir dizinden veya sıralama düzeninden bağımsız. Bir yaptığınızda ORDER BY y DESC, önce en yüksek y değerine sahip satırları alırsınız. Bu otomatik oluşturulmuş bir kimlik ise, diğer cevaplarda önerildiği gibi tabloya en son eklenen kayıtları göstermelidir. Ancak:

  • Bu yalnızca otomatik olarak oluşturulmuş bir kimlik sütunu varsa çalışır
  • Bunu TOPişlevle karşılaştırırsanız önemli bir performans etkisi vardır.

Doğru cevap TOP, alt satırları elde etmek için bir eşdeğer olmadığı ve olamaz olmalıdır .


3
Doğru, eşdeğeri yok gibi görünüyor, sadece geçici çözümler.
dürtmek

4
TOP'un bir tabloya hangi öğelerin eklendiği sırayla ilgisi yoktur, bu yalnızca "Sorgumla eşleşen ilk X kaydını ver" anlamına gelir
Luke

4
Evet yapar, size sorgunuzla eşleşen tabloya eklenen ilk kayıtları verir.
Martijn Burger

4
Luke'a katılıyorum. Veritabanı tabloları tanım gereği sırasızdır. Select deyiminin ORDER BY yan tümcesi olmadığında RDBMS tarafından sağlanan sıraya asla güvenilmemelidir. wiki'de buradan okuyun Ancak, veritabanı sistemi, tabloyu sorgulayan SELECT deyiminde bir ORDER BY yan tümcesi belirtilmediği sürece satırların sıralanmasını garanti etmez.
Zohar Peled

2
Bu yanıta katılıyorum, ancak pratikte Tom'un cevabı sorunu tüm pratik kullanımlar için çözüyor.
Antonio

18

Mantıksal olarak,

BOTTOM (x) is all the records except TOP (n - x), where n is the count; x <= n

Örneğin, Çalışandan Alt 1000'i seçin:

T-SQL'de,

DECLARE 
@bottom int,
@count int

SET @bottom = 1000 
SET @count = (select COUNT(*) from Employee)

select * from Employee emp where emp.EmployeeID not in 
(
SELECT TOP (@count-@bottom) Employee.EmployeeID FROM Employee
)

1
Merhaba shadi2014, "ORDER BY" kullanmadan sonuç bir şekilde rastgele olacaktır.
bummi

5
bummi, haklısın, ama bu cevabı doğru yapan da bu. Teorik olarak ÜST'ü seçmenin kendisi "rastgele" dir ve bu, ALT SEÇİM için doğru uygulamadır. 5000 kayıttan oluşan bir tabloda, en alt 1000, ilk 4000 hariç her şeydir.
tzachs

9

Görünüşe göre çözümde ORDER BY cümlesini uygulayan yanıtlardan herhangi biri noktayı kaçırıyor veya TOP'un size ne döndürdüğünü gerçekten anlamıyor.

TOP, kayıt kümesini döndürülen ilk N kayıtla sınırlayan sırasız bir sorgu sonuç kümesi döndürür. (Oracle açısından bakıldığında, bir ROWNUM <(N + 1) eklemeye benzer.

Bir sipariş kullanan herhangi bir çözelti, olabilir tarafından amacıyla kullanılmıştır hangi kriterlere bağlı olarak, (bu veri seti, birinci etapta sırasız beri), UOP maddesi tarafından döndürülen satır döndürür

TOP'un faydası, veri kümesi belirli bir N boyutuna ulaştığında satırları getirmeyi durdurmasıdır. Hepsini almak zorunda kalmadan verilerin neye benzediğine dair bir fikir edinebilirsiniz.

BOTTOM'u doğru bir şekilde uygulamak için, tüm veri kümesini sırasız olarak getirmesi ve ardından veri kümesini son N kayıtla sınırlaması gerekir. Büyük masalarla uğraşıyorsanız bu özellikle etkili olmayacaktır. Size istediğinizi düşündüğünüz şeyi de vermeyecektir . Veri kümesinin sonu mutlaka "eklenen son satırlar" olmayabilir (ve muhtemelen DML yoğun uygulamaların çoğu için olmayacaktır).

Benzer şekilde, ORDER BY uygulayan çözümler, ne yazık ki, büyük veri kümeleriyle uğraşırken felaket olabilir. Diyelim ki 10 Milyar plağım varsa ve son 10'unu istiyorsam, 10 Milyar kayıt sipariş edip son 10'u seçmek oldukça aptalca.

Buradaki sorun, BOTTOM'un onu TOP ile karşılaştırırken düşündüğümüz anlama sahip olmamasıdır .

Kayıtlar tekrar tekrar eklendiğinde, silindiğinde, eklendiğinde, silindiğinde, depoda bazı boşluklar görünecek ve mümkünse daha sonra satırlar yerleştirilecektir. Ancak, TOP'u seçtiğimizde sıklıkla gördüğümüz şey, sıralı veriler olarak görünür , çünkü tablonun varlığının başlarında eklenmiş olabilir. Tabloda çok fazla silinme görülmezse , sıralı görünebilir . (örneğin, oluşturma tarihleri, tablonun oluşturulmasının kendisi kadar geçmiş olabilir). Ancak gerçek şu ki, eğer bu çok fazla silinen bir tabloysa, TOP N satırları hiç böyle görünmeyebilir.

Yani - buradaki sonuç (kelime anlamı), BOTTOM N kayıtlarını isteyen birinin aslında ne istediğini bilmediğidir. Ya da en azından ne istedikleri ve BOTTOM'un gerçekte ne anlama geldiği aynı şey değil.

Yani - çözüm, talepte bulunan kişinin gerçek iş ihtiyacını karşılayabilir ... ancak ALT olmak için kriterleri karşılamıyor.


1
Mükemmel açıklama. Konuya daha fazla ışık tutmak için oy verin.
rohrl77

Benim kullanım durumum bu. insertSatırları dizine eklenmemiş büyük bir tabloya koymak için büyük bir açıklama yaptım . (Tabloyu indekslemeye başlamadan önce dolduruyorum.) Müşteri oturumumu bir yeniden başlatma veya herhangi bir nedenle kaybettim ve şimdi yeni eklenen satırlarımın orada olup olmadığını görmek istiyorum. Tablonun 'alt' satırı en son satırlarımdan biriyse, işlemin tamamlandığını biliyorum. Eğer 'alt' sıra başka bir şeyse, hiçbir garanti yok ve emin olmak için tüm tabloyu taramalıyım ... ama büyük olasılıkla, 'alt' satırını hızlıca kontrol ederek biraz zaman kazanabilirim. üst'.
Ed Avis

İyi bir açıklama, ancak yine de verilerin tersine okunmasını / geri alınmasını gerektiren bir tabanın varlığını ima ediyor. Yeni bir tablodaki (kabul edilen uçta) iptal edilmiş bir ekleme durumunda, eklenen son kaydı (altta) her şeyi almadan doğrulamak faydalı olacaktır. Tablo verilerinin ters sırada alınamamasının teknik bir nedeni var mı?
James

3

Şu anda "Justin Ethier" tarafından kabul edilen cevap, "Koruyucu Bir" tarafından işaret edildiği gibi doğru bir cevap değil.

Görebildiğim kadarıyla, şu an için başka hiçbir yanıt veya yorum, soru yazarının sorduğu BOTTOM (x) 'e eşdeğer değildir.

Öncelikle, bu işlevselliğin gerekli olacağı bir senaryo düşünelim:

SELECT * FROM Split('apple,orange,banana,apple,lime',',')

Bu, bir sütun ve beş kayıttan oluşan bir tablo döndürür:

  • elma
  • Portakal
  • muz
  • elma
  • Misket Limonu

Gördüğünüz gibi: bir kimlik sütunumuz yok; döndürülen sütuna göre sıralayamayız; ve ilk iki kayıt için yaptığımız gibi standart SQL kullanarak alttaki iki kaydı seçemiyoruz.

İşte bir çözüm sunma girişimim:

SELECT * INTO #mytemptable FROM Split('apple,orange,banana,apple,lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
SELECT TOP 2 * FROM #mytemptable ORDER BY tempID DESC
DROP TABLE #mytemptable

Ve işte daha eksiksiz bir çözüm:

SELECT * INTO #mytemptable FROM Split('apple,orange,banana,apple,lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
DELETE FROM #mytemptable WHERE tempID <= ((SELECT COUNT(*) FROM #mytemptable) - 2)
ALTER TABLE #mytemptable DROP COLUMN tempID
SELECT * FROM #mytemptable
DROP TABLE #mytemptable

Hiçbir şekilde bunun her koşulda kullanılmasının iyi bir fikir olduğunu iddia etmiyorum, ancak istenen sonuçları sağlıyor.



1

Diğer şekilde sıralamanın sorunu, genellikle endeksleri iyi kullanmamasıdır. Ayrıca, başında veya sonunda olmayan birkaç satır seçmeniz gerekirse, çok da genişletilemez. Alternatif bir yol aşağıdaki gibidir.

DECLARE @NumberOfRows int;
SET @NumberOfRows = (SELECT COUNT(*) FROM TheTable);

SELECT col1, col2,...
FROM (
    SELECT col1, col2,..., ROW_NUMBER() OVER (ORDER BY col1) AS intRow
    FROM TheTable
) AS T
WHERE intRow > @NumberOfRows - 20;

2
1) ORDER BY yan tümcenizin yönünü değiştirmek "endeksleri iyi kullanmıyorsa", o zaman iyi bir RDBMS edinin! RDBMS, dizinde ileriye mi yoksa geriye mi gidip gitmeyeceğini asla önemsememelidir. 2) Dizin kullanımıyla ilgili endişeleriniz var, ancak çözümünüz tablodaki her satıra bir sıra ekliyor ... Bu, uygun bir dizinin KULLANILMAMASINI garantilemenin bir yolu.
Hayal kırıklığına uğramış

1

Yukarıdaki "Tom H" yanıtı doğru ve Alt 5 satırları almakta benim için çalışıyor.

SELECT [KeyCol1], [KeyCol2], [Col3]
FROM
(SELECT TOP 5 [KeyCol1],
       [KeyCol2],
       [Col3]
  FROM [dbo].[table_name]
  ORDER BY [KeyCol1],[KeyCol2] DESC) SOME_ALAIS
  ORDER BY [KeyCol1],[KeyCol2] ASC

Teşekkürler.


0

bunu dene.

declare @floor int --this is the offset from the bottom, the number of results to exclude
declare @resultLimit int --the number of results actually retrieved for use
declare @total int --just adds them up, the total number of results fetched initially

--following is for gathering top 60 results total, then getting rid of top 50. We only keep the last 10
set @floor = 50 
set @resultLimit = 10
set @total = @floor + @resultLimit

declare @tmp0 table(
    --table body
)

declare @tmp1 table(
    --table body
)

--this line will drop the wanted results from whatever table we're selecting from
insert into @tmp0
select Top @total --what to select (the where, from, etc)

--using floor, insert the part we don't want into the second tmp table
insert into @tmp1
select top @floor * from @tmp0

--using select except, exclude top x results from the query
select * from @tmp0
except 
select * from @tmp1

OP için kodunuz nedir? Lütfen sorunu nasıl çözmeye çalıştığınıza dair biraz daha açıklama ekleyin
techspider

Bir düzenleme yaptım. Umarım daha fazla yorum ekleyerek bunu biraz daha iyi açıklar. Ana fikir, bir tablodan en üstteki x'i seçmek, ardından en çok istenen x - num'u seçmek, sonra da gereksiz sonuçları dışarıda bırakmak için bir exclu ifadesi kullanmaktır.
HumbleWebDev

0

Buna, geri dönen satır sayısını bilmenizi gerektirmeyen bir çözüm buldum.

Örneğin, en son 1 (veya 2 veya 5 veya 34) dışındaki tüm konumların bir tabloda oturum açmasını istiyorsanız

SELECT * 
FROM
    (SELECT ROW_NUMBER() OVER (ORDER BY CreatedDate) AS Row, * 
    FROM Locations
    WHERE UserId = 12345) AS SubQuery
WHERE Row > 1 -- or 2, or 5, or 34

0

Azalan şekilde sıralanmış basit bir alt sorguyu sorgulamak ve ardından aynı sütunda artan şekilde sıralamak hile yapar.

SELECT * FROM 
    (SELECT TOP 200 * FROM [table] t2 ORDER BY t2.[column] DESC) t1
    ORDER BY t1.[column]

0
SELECT TOP 10*from TABLE1 ORDER BY ID DESC

Kimlik, TABLO1'in birincil anahtarıdır.


0

İlk olarak, aşağıdakileri kullanarak tablonun orijinal sırasına göre bir alt sorguda bir dizin oluşturun:

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

Ardından tabloyu RowIndex, ana sorguda oluşturduğunuz sütuna göre azalan şekilde sıralayın :

ORDER BY RowIndex DESC

Ve son olarak TOPistediğiniz sayıda satırla kullanın:

    SELECT TOP 1 * --(or 2, or 5, or 34)
    FROM   (SELECT ROW_NUMBER() OVER (ORDER BY  (SELECT NULL) ) AS RowIndex, * 
            FROM MyTable) AS SubQuery
    ORDER BY RowIndex DESC
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.