Bagaimana cara memilih baris secara acak dalam SQL?

226

Saya menggunakan MSSQL Server 2005. Dalam db saya, saya memiliki tabel "customerNames" yang memiliki dua kolom "Id" dan "Name" dan kira-kira. 1.000 hasil.

Saya membuat fungsionalitas di mana saya harus memilih 5 pelanggan secara acak setiap waktu. Adakah yang bisa memberi tahu saya cara membuat kueri yang akan mendapatkan 5 baris acak (Id, dan Nama) setiap kali ketika kueri dieksekusi?

Prashant
sumber
Acak bukan persyaratan umum untuk database, saya terkejut menemukan link yang untuk beberapa SQL
Paxic
2
Tergantung pada seberapa banyak keacakan yang Anda inginkan. Lihat: msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx untuk perbandingan NEW_ID versus RAND ()
Shannon Severance

Jawaban:

639
SELECT TOP 5 Id, Name FROM customerNames
ORDER BY NEWID()

Yang mengatakan, semua orang tampaknya datang ke halaman ini untuk jawaban yang lebih umum untuk pertanyaan Anda:

Memilih baris acak dalam SQL

Pilih baris acak dengan MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Pilih baris acak dengan PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Pilih baris acak dengan Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Pilih baris acak dengan IBM DB2

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

Pilih catatan acak dengan Oracle:

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1

Pilih baris acak dengan sqlite:

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1
Curtis Tasker
sumber
3
+1 untuk mem-posting jawaban secara langsung di SO daripada menautkan ke situs eksternal (seperti jawaban yang diterima) yang bisa saja turun ketika pengguna di masa depan melihat pertanyaan ini.
Ray Zhou
17
Apakah ini menjadi sangat mahal pada tabel besar, di mana setiap baris mendapat nomor acak, dan kemudian set angka acak besar yang tidak diindeks diurutkan?
Andrey
Ini mungkin jelas bagi kebanyakan orang, tetapi tidak jelas bagi saya ... kueri berikut tidak akan mendapatkan nilai acak baru untuk setiap baris: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) - sunting: Saya tidak dapat memformat agar berfungsi dalam komentar :(
Mir
Anda Genius! Saya sangat membenci Anda karena saya tidak melihat ini sampai saya pergi dan menulis permintaan yang sangat panjang dengan sub kueri dan nomor baris.
greenkode
5
Peringatan: Untuk database besar, metode ini akan memiliki kinerja yang buruk. Bisakah Anda bayangkan waktu yang diperlukan untuk menghasilkan nilai acak untuk setiap baris jika database memiliki jutaan entri? Anda dapat memiliki lebih banyak informasi tentang dan alternatif yang lebih baik di sini .
Francis Ngueukam
35
SELECT TOP 5 Id, Name FROM customerNames ORDER BY NEWID()
Cody Caughlan
sumber
11

Jika seseorang menginginkan solusi PostgreSQL:

select id, name
from customer
order by random()
limit 5;
Barry Brown
sumber
Jawaban ini bagus untuk PostgreSQL, tidak perlu batas.
aliasbody
9

Mungkin situs ini akan membantu.

Bagi mereka yang tidak ingin mengklik:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

sumber
2
setidaknya harus diganti 1 dengan 5 :)
268 roman m
5

Jika Anda memiliki meja dengan jutaan baris dan peduli dengan kinerja, ini bisa menjadi jawaban yang lebih baik:

SELECT * FROM Table1
WHERE (ABS(CAST(
  (BINARY_CHECKSUM
  (keycol1, NEWID())) as int))
  % 100) < 10

https://msdn.microsoft.com/en-us/library/cc441928.aspx

Tohid
sumber
Perhatikan bahwa ini akan memilih sekitar 10% dari baris dalam tabel. Jika Anda perlu memilih jumlah baris yang tepat, atau setidaknya N baris, pendekatan ini tidak akan berhasil.
LarsH
4

Ini adalah pertanyaan lama, tetapi mencoba menerapkan bidang baru (baik NEWID () atau ORDER BY rand ()) ke tabel dengan banyak baris akan sangat mahal. Jika Anda memiliki tambahan, ID unik (dan tidak memiliki lubang) akan lebih efisien untuk menghitung X # ID yang akan dipilih daripada menerapkan GUID atau mirip dengan setiap baris tunggal dan kemudian mengambil X # atas.

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];

DECLARE @randomId1 int, @randomId2 int, @randomId3 int, @randomId4 int, @randomId5 int
SET @randomId1 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId2 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId3 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId4 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId5 = ((@maxValue + 1) - @minValue) * Rand() + @minValue

--select @maxValue as MaxValue, @minValue as MinValue
--  , @randomId1 as SelectedId1
--  , @randomId2 as SelectedId2
--  , @randomId3 as SelectedId3
--  , @randomId4 as SelectedId4
--  , @randomId5 as SelectedId5

select * from [TABLE] el
where el.id in (@randomId1, @randomId2, @randomId3, @randomId4, @randomId5)

Jika Anda ingin memilih lebih banyak baris, saya akan mencari populasi #tempTable dengan ID dan sekelompok nilai rand () kemudian menggunakan setiap nilai rand () untuk menskala ke nilai min-max. Dengan begitu Anda tidak perlu mendefinisikan semua parameter @ randomId1 ... n. Saya telah memasukkan contoh di bawah ini menggunakan CTE untuk mengisi tabel awal.

DECLARE @NumItems int = 100;

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];
DECLARE @range int = @maxValue+1 - @minValue;

with cte (n) as (
   select 1 union all
   select n+1 from cte
   where n < @NumItems
)
select cast( @range * rand(cast(newid() as varbinary(100))) + @minValue as int) tp
into #Nt
from cte;

select * from #Nt ntt
inner join [TABLE] i on i.id = ntt.tp;

drop table #Nt;
RIanGillis
sumber
@Protiguous, hasil edit yang Anda ajukan melanggar pilihan acak. Menggunakan min () dan maks () yang diterapkan pada tabel dbo.Tally64k tidak akan memungkinkan pengguna untuk memilih baris dengan id pk> 65556.
RIanGillis
Perubahan nama tabel hanyalah sebuah artefak dari pengujian. Nama tabel sebenarnya tidak masalah, selama tabel yang benar digunakan. min () dan max () dapat keduanya ditanyakan dalam satu permintaan, bukan dua, yang saya coba tunjukkan.
Berlipat
@Protiguous Ah, saya mengerti sekarang, saya bingung karena Anda menggunakan 0-65k saat melakukan min-max tetapi tidak lebih lambat. Setelah hasil edit Anda yang terbaru, saya sebenarnya ingin bertanya tentang implikasi kinerja dari perubahan yang Anda buat, karena penyesuaian kinerja adalah salah satu minat saya dan keputusan yang tampaknya tidak berarti seperti sisi mana yang sama dengan tanda Anda menempatkan sesuatu yang sebenarnya dapat memiliki dampak signifikan - - Apakah hal yang sama berlaku untuk 5 SET @ randomId ## panggilan? Atau apakah itu berbeda karena tidak MEMILIH DARI tabel yang sebenarnya?
RIanGillis
Saya tidak yakin saya mengerti pertanyaan Anda. Apakah Anda bertanya mengapa ada 5 SET, bukan hanya 1 SELECT @ id1 = rand (), @ id2 = rand () ..? Itu karena beberapa panggilan ke rand () dalam 1 pernyataan akan menghasilkan hasil yang sama, maka SET yang terpisah. (rand () pada SQL Server adalah fungsi deterministik, saya percaya.) Saya kira 1 set vs 5 set berada dalam kisaran kinerja nanosecond.
Protiguous
4
SELECT * FROM TABLENAME ORDER BY random() LIMIT 5; 
Narendra
sumber
Pertanyaan lama, tetapi jawaban ini tidak berjalan untuk saya di Oracle.
Beruang
SELECT * FROM (SELECT * FROM table ORDER BY DBMS_RANDOM.VALUE) WHERE rownum <number; @Bear coba ini
Narendra
3

Saya menemukan ini berfungsi paling baik untuk big data.

SELECT TOP 1 Column_Name FROM dbo.Table TABLESAMPLE(1 PERCENT);

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT) acak tetapi perlu menambahkan TOP n untuk mendapatkan ukuran sampel yang benar.

Penggunaannya NEWID()sangat lambat pada tabel besar.

Billy
sumber
0

Seperti yang saya jelaskan di artikel ini , untuk mengocok set hasil SQL, Anda perlu menggunakan panggilan fungsi database-spesifik.

Perhatikan bahwa mengurutkan set hasil besar menggunakan fungsi RANDOM mungkin menjadi sangat lambat, jadi pastikan Anda melakukannya pada set hasil kecil.

Jika Anda harus mengocok set hasil yang besar dan membatasi setelahnya, maka lebih baik menggunakan sesuatu seperti OracleSAMPLE(N) atau TABLESAMPLEdi SQL Server atau PostgreSQL daripada fungsi acak di klausa ORDER BY.

Jadi, anggap kita memiliki tabel database berikut:

masukkan deskripsi gambar di sini

Dan baris-baris berikut dalam songtabel:

| id | artist                          | title                              |
|----|---------------------------------|------------------------------------|
| 1  | Miyagi & Эндшпиль ft. Рем Дигга | I Got Love                         |
| 2  | HAIM                            | Don't Save Me (Cyril Hahn Remix)   |
| 3  | 2Pac ft. DMX                    | Rise Of A Champion (GalilHD Remix) |
| 4  | Ed Sheeran & Passenger          | No Diggity (Kygo Remix)            |
| 5  | JP Cooper ft. Mali-Koa          | All This Love                      |

Peramal

Di Oracle, Anda perlu menggunakan DBMS_RANDOM.VALUEfungsi, seperti yang diilustrasikan oleh contoh berikut:

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY DBMS_RANDOM.VALUE

Saat menjalankan kueri SQL yang disebutkan di Oracle, kita akan mendapatkan hasil sebagai berikut:

| song                                              |
|---------------------------------------------------|
| JP Cooper ft. Mali-Koa - All This Love            |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

Perhatikan bahwa lagu sedang terdaftar dalam urutan acak, berkat DBMS_RANDOM.VALUEpanggilan fungsi yang digunakan oleh klausa ORDER BY.

SQL Server

Pada SQL Server, Anda perlu menggunakan NEWIDfungsi, seperti yang diilustrasikan oleh contoh berikut:

SELECT
    CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY NEWID()

Saat menjalankan kueri SQL yang disebutkan di SQL Server, kita akan mendapatkan set hasil berikut:

| song                                              |
|---------------------------------------------------|
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| JP Cooper ft. Mali-Koa - All This Love            |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |

Perhatikan bahwa lagu sedang terdaftar dalam urutan acak, berkat NEWIDpanggilan fungsi yang digunakan oleh klausa ORDER BY.

PostgreSQL

Pada PostgreSQL, Anda perlu menggunakan randomfungsi, seperti yang diilustrasikan oleh contoh berikut:

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY random()

Saat menjalankan kueri SQL yang disebutkan di PostgreSQL, kita akan mendapatkan hasil sebagai berikut:

| song                                              |
|---------------------------------------------------|
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

Perhatikan bahwa lagu sedang terdaftar dalam urutan acak, berkat randompanggilan fungsi yang digunakan oleh klausa ORDER BY.

MySQL

Di MySQL, Anda perlu menggunakan RANDfungsinya, seperti yang diilustrasikan oleh contoh berikut:

SELECT
  CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY RAND()

Saat menjalankan kueri SQL yang disebutkan di MySQL, kita akan mendapatkan hasil sebagai berikut:

| song                                              |
|---------------------------------------------------|
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |

Perhatikan bahwa lagu sedang terdaftar dalam urutan acak, berkat RANDpanggilan fungsi yang digunakan oleh klausa ORDER BY.

Vlad Mihalcea
sumber
0

Jika Anda menggunakan tabel besar dan ingin mengakses 10 persen dari data kemudian jalankan perintah berikut ini: SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

Palash Mondal
sumber