Bagaimana cara memilih baris paling bawah?

100

Saya dapat melakukan SELECT TOP (200) ... tetapi mengapa tidak BAWAH (200)?

Bukan untuk masuk ke filosofi yang saya maksud adalah, bagaimana saya bisa melakukan yang setara dengan TOP (200) tetapi secara terbalik (dari bawah, seperti yang Anda harapkan BAWAH lakukan ...)?

CloudMeta
sumber

Jawaban:

89
SELECT
    columns
FROM
(
     SELECT TOP 200
          columns
     FROM
          My_Table
     ORDER BY
          a_column DESC
) SQ
ORDER BY
     a_column ASC
Tom H.
sumber
2
Mengapa Anda menggunakan tabel turunan?
RichardOD
14
Jika Anda ingin mengembalikan baris dalam urutan A-> Z, tetapi memilih 200 teratas dalam urutan Z-> A, ini adalah salah satu cara untuk melakukannya. Jawaban lain, menyarankan hanya mengubah ORDER BY tidak akan mengembalikan hasil yang sama seperti yang dijelaskan dalam pertanyaan, karena akan rusak (kecuali urutan tidak menjadi masalah, yang tidak dikatakan oleh OP).
Tom H
3
@ Tom H. Harus berpikir beberapa detik tentang apa yang Anda maksud (saya sudah bangun 14 jam). Awalnya saya tidak bisa melihat perbedaan antara pesanan Anda dan urutan berdasarkan jawaban, tetapi sekarang saya bisa. Jadi +1.
RichardOD
1
Ini dan jawaban lainnya berfungsi dengan baik saat Anda mengerjakan tabel yang lebih kecil. Menurut saya tidak ada gunanya memesan seluruh tabel dengan kolom ketika Anda hanya tertarik pada beberapa baris terbawah.
ikan mantap
1
jawaban yang bagus, imho terbaik ... masalah sebenarnya adalah saya tidak dapat melakukan ini dari skrip ASP, jadi saya pikir saya perlu menyusun ulang objRecordset secara manual atau dengan fungsi yang disediakan ASP ....
Andrea_86
98

Itu tidak perlu. Anda dapat menggunakan ORDER BYdan hanya mengubah pengurutan DESCuntuk mendapatkan efek yang sama.

Justin Ethier
sumber
3
google mengatakan hal yang sama dan sekarang 9 dari Anda setuju, cukup baik untuk saya, terima kasih: D
CloudMeta
9
Menggunakan DESC akan mengembalikan N baris terakhir, tetapi baris yang dikembalikan juga akan berada dalam urutan terbalik dari N baris pertama.
RickNZ
11
Bagaimana jika tidak ada indeks di tabel Anda untuk ORDER BY?
Pelindung satu
8
@Justin: Bayangkan hanya memiliki satu kolom, berisi nilai varchar. ORDER BY akan mengurutkan menurut abjad, yang (mungkin) bukan yang kita inginkan.
Pelindung satu
3
Tom H. adalah jawaban yang benar, jika tidak, urutan baris Anda akan terbalik.
Pierre-Olivier Goulet
39

Maaf, tapi menurut saya saya tidak melihat jawaban yang benar menurut pendapat saya.

Fungsi TOPx menunjukkan catatan dalam urutan yang tidak ditentukan. Dari definisi tersebut BOTTOMdapat disimpulkan bahwa suatu fungsi tidak dapat didefinisikan.

Independen indeks atau urutan apa pun. Ketika Anda melakukannya, ORDER BY y DESCAnda mendapatkan baris dengan nilai y tertinggi terlebih dahulu. Jika ini adalah ID yang dibuat secara otomatis, itu harus menunjukkan catatan yang terakhir ditambahkan ke tabel, seperti yang disarankan dalam jawaban lain. Namun:

  • Ini hanya berfungsi jika ada kolom id yang dibuat secara otomatis
  • Ini memiliki dampak kinerja yang signifikan jika Anda membandingkannya dengan TOPfungsinya

Jawaban yang benar adalah bahwa tidak ada, dan tidak mungkin, setara dengan TOPmendapatkan baris terbawah.

Martijn Burger
sumber
3
Benar, sepertinya tidak ada padanan, hanya solusi.
aduk
4
TOP tidak ada hubungannya dengan urutan item yang ditambahkan ke tabel itu hanya berarti "Berikan X record pertama yang cocok dengan kueri saya"
Luke
4
Ya, ini memberi Anda rekaman pertama yang ditambahkan ke tabel yang cocok dengan kueri Anda.
Martijn Burger
4
Saya setuju dengan Luke. Tabel database tidak memiliki urutan menurut definisi. Seseorang tidak boleh bergantung pada urutan yang disediakan oleh RDBMS ketika pernyataan pilih tidak memiliki klausul ORDER BY. baca di sini di wiki Bagaimanapun, sistem database tidak menjamin pengurutan baris apa pun kecuali klausa ORDER BY ditentukan dalam pernyataan SELECT yang menanyakan tabel.
Zohar Peled
2
Saya setuju dengan jawaban ini, tetapi dalam praktiknya , jawaban Tom memecahkan masalah untuk semua penggunaan praktis.
Antonio
18

Secara logis,

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

Misalnya Pilih 1000 Terbawah dari Karyawan:

Di T-SQL,

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
)
Shadi Namrouti
sumber
1
Hi shadi2014, tanpa menggunakan "ORDER BY", hasil Anda akan acak.
bummi
5
bummi, kamu benar, tapi itulah yang membuat jawaban ini benar. Pilih TOP sendiri secara teori "acak", dan ini adalah implementasi yang benar untuk Select BOTTOM. Dalam tabel 5000 catatan, 1000 terbawah adalah segalanya kecuali 4000 teratas.
tzachs
9

Tampaknya salah satu jawaban yang menerapkan klausa ORDER BY dalam solusi kehilangan intinya, atau tidak benar-benar memahami apa yang dikembalikan TOP kepada Anda.

TOP mengembalikan kumpulan hasil kueri tidak berurutan yang membatasi kumpulan rekaman ke catatan N pertama yang dikembalikan. (Dari perspektif Oracle, ini mirip dengan menambahkan tempat ROWNUM <(N + 1).

Solusi apa pun yang menggunakan urutan, dapat mengembalikan baris yang juga dikembalikan oleh klausa TOP (karena kumpulan data itu tidak diurutkan di tempat pertama), bergantung pada kriteria apa yang digunakan dalam urutan oleh

Kegunaan TOP adalah setelah dataset mencapai ukuran N tertentu, ia berhenti mengambil baris. Anda bisa merasakan seperti apa data itu tanpa harus mengambil semuanya.

Untuk mengimplementasikan BOTTOM secara akurat, itu perlu mengambil seluruh dataset tanpa urutan dan kemudian membatasi dataset ke N record akhir. Itu tidak akan efektif jika Anda berurusan dengan tabel besar. Juga tidak akan memberi Anda apa yang menurut Anda Anda minta. Akhir dari kumpulan data mungkin tidak selalu berupa "baris terakhir yang disisipkan" (dan mungkin tidak untuk sebagian besar aplikasi intensif DML).

Demikian pula, solusi yang menerapkan ORDER BY, sayangnya, berpotensi menjadi bencana saat menangani kumpulan data yang besar. Jika saya memiliki, katakanlah, 10 Miliar rekaman dan menginginkan 10 Miliar rekaman terakhir, sangatlah bodoh untuk memesan 10 Miliar rekaman dan memilih 10 yang terakhir.

Masalahnya di sini, BOTTOM tidak memiliki arti seperti yang kita pikirkan saat membandingkannya dengan TOP.

Saat catatan dimasukkan, dihapus, disisipkan, dihapus berulang kali, beberapa celah akan muncul di penyimpanan dan kemudian, baris akan ditempatkan, jika memungkinkan. Namun yang sering kita lihat, ketika kita memilih TOP, ternyata data sudah terurut, karena mungkin sudah disisipkan lebih awal pada keberadaan tabel. Jika tabel tidak mengalami banyak penghapusan, tabel tersebut mungkin tampak teratur. (mis. tanggal pembuatan mungkin sejauh pembuatan tabel itu sendiri). Tetapi kenyataannya adalah, jika ini adalah tabel dengan penghapusan berat, baris TOP N mungkin tidak terlihat seperti itu sama sekali.

Jadi - intinya di sini (permainan kata-kata) adalah bahwa seseorang yang meminta catatan BOTTOM N sebenarnya tidak tahu apa yang mereka minta. Atau, setidaknya, apa yang mereka minta dan apa arti BAWAH sebenarnya bukanlah hal yang sama.

Jadi - solusinya mungkin memenuhi kebutuhan bisnis sebenarnya dari pemohon ... tetapi tidak memenuhi kriteria untuk menjadi BAWAH.

pengguna9323238
sumber
1
Penjelasan yang bagus. Beri suara positif untuk menjelaskan lebih banyak topik.
rohrl77
Kasus penggunaan saya adalah ini. Saya menjalankan insertpernyataan besar untuk menempatkan baris ke dalam tabel besar yang tidak terindeks. (Saya mengisi tabel terlebih dahulu sebelum saya mulai mengindeksnya.) Saya kehilangan sesi klien saya karena reboot atau apa pun, dan sekarang saya ingin melihat apakah baris yang baru saya tambahkan ada di sana. Jika baris 'terbawah' di tabel adalah salah satu baris terbaru saya, saya tahu operasi telah selesai. Jika baris 'bawah' adalah sesuatu yang lain, yah tidak ada jaminan dan saya harus memindai seluruh tabel untuk memastikan ... tetapi kemungkinan besar saya dapat menghemat waktu dengan segera memeriksa 'bawah' seperti yang Anda bisa ' puncak'.
Ed Avis
Penjelasan yang bagus, tetapi tetap menyiratkan adanya dasar, yang hanya membutuhkan data untuk dibaca / diambil secara terbalik. Dalam kasus (admitteedly edge) dari sisipan yang dibatalkan pada tabel baru, memverifikasi catatan terakhir yang dimasukkan (bagian bawah) tanpa mengambil semuanya akan berguna. Apakah ada alasan teknis mengapa data tabel tidak dapat diambil dalam urutan terbalik?
James
3

Jawaban yang diterima saat ini oleh "Justin Ethier" bukanlah jawaban yang benar seperti yang ditunjukkan oleh "Pelindung satu".

Sejauh yang saya bisa lihat, sampai sekarang, tidak ada jawaban atau komentar lain yang setara dengan BAWAH (x) pertanyaan yang diminta penulis.

Pertama, mari pertimbangkan skenario di mana fungsionalitas ini akan dibutuhkan:

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

Ini mengembalikan tabel satu kolom dan lima catatan:

  • apel
  • jeruk
  • pisang
  • apel
  • jeruk nipis

Seperti yang Anda lihat: kami tidak memiliki kolom ID; kami tidak dapat memesan berdasarkan kolom yang dikembalikan; dan kami tidak dapat memilih dua rekaman terbawah menggunakan SQL standar seperti yang dapat kami lakukan untuk dua rekaman teratas.

Inilah usaha saya untuk memberikan solusi:

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

Dan berikut ini solusi yang lebih lengkap:

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

Saya sama sekali tidak mengklaim bahwa ini adalah ide yang baik untuk digunakan dalam semua keadaan, tetapi ini memberikan hasil yang diinginkan.

tomosius
sumber
1

Yang perlu Anda lakukan adalah membalik file ORDER BY. Tambahkan atau hapus DESC.

Justin Swartsel
sumber
1

Masalah dengan memesan dengan cara lain adalah sering tidak memanfaatkan indeks dengan baik. Ini juga tidak terlalu dapat diperpanjang jika Anda perlu memilih sejumlah baris yang tidak di awal atau di akhir. Cara alternatifnya adalah sebagai berikut.

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;
Paul
sumber
2
1) Jika mengubah arah klausa ORDER BY Anda "tidak memanfaatkan indeks dengan baik", dapatkan RDBMS yang layak! RDBMS tidak boleh peduli apakah itu menavigasi indeks maju atau mundur. 2) Anda khawatir tentang penggunaan indeks, namun solusi Anda melampirkan urutan ke setiap baris dalam tabel ... Itu salah satu cara untuk menjamin indeks yang sesuai TIDAK akan digunakan.
Kecewa
1

Jawaban "Tom H" di atas benar dan berhasil untuk saya dalam mendapatkan 5 baris Terbawah.

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

Terima kasih.

pengguna3598017
sumber
0

coba ini.

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
HumbleWebDev
sumber
apa yang membuat kode Anda untuk OP? Harap tambahkan sedikit lagi penjelasan tentang cara Anda mencoba menyelesaikan masalah
techspider
Saya membuat edit. Saya harap ini menjelaskannya sedikit lebih baik, menambahkan lebih banyak komentar. Ide utamanya adalah memilih x teratas dari tabel, kemudian memilih x - num teratas yang diinginkan, kemudian menggunakan pernyataan kecuali untuk mengeluarkan hasil yang tidak dibutuhkan.
HumbleWebDev
0

Saya telah menemukan solusi untuk ini yang tidak mengharuskan Anda mengetahui jumlah baris yang dikembalikan.

Misalnya, jika Anda ingin mendapatkan semua lokasi yang dicatat dalam tabel, kecuali yang terbaru 1 (atau 2, atau 5, atau 34)

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
Merah
sumber
0

Membuat kueri subkueri sederhana yang diurutkan menurun, diikuti dengan mengurutkan pada kolom yang sama ke atas melakukan triknya.

SELECT * FROM 
    (SELECT TOP 200 * FROM [table] t2 ORDER BY t2.[column] DESC) t1
    ORDER BY t1.[column]
sheppe
sumber
0
SELECT TOP 10*from TABLE1 ORDER BY ID DESC

Dimana ID adalah kunci utama dari TABLE1.

Er. Binod Mehta
sumber
0

Pertama, buat indeks di subkueri sesuai dengan urutan asli tabel menggunakan:

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

Kemudian urutkan tabel dengan RowIndexkolom yang Anda buat di kueri utama:

ORDER BY RowIndex DESC

Dan akhirnya gunakan TOPdengan jumlah baris yang Anda inginkan:

    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
Thiago Marques
sumber