Làm thế nào để yêu cầu một hàng ngẫu nhiên trong SQL?


510

Làm cách nào tôi có thể yêu cầu một hàng ngẫu nhiên (hoặc càng gần với ngẫu nhiên thực sự càng tốt) trong SQL thuần túy?


tôi đã luôn luôn làm điều này trong php sau khi kết quả truy vấn từ sql ... điều này có thể nhanh hơn rất nhiều để xử lý theo phụ lục giới hạn 1 của giải pháp
CheeseConQueso


2
Dường như không có giải pháp "SQL thuần túy" nào chạy trên mọi dbms ... có một giải pháp cho mỗi trong số chúng.
Manu

Phiên bản hiệu suất: stackoverflow.com/questions/4329394/
Mạnh

Câu trả lời:


735

Xem bài đăng này: SQL để chọn một hàng ngẫu nhiên từ bảng cơ sở dữ liệu . Nó đi qua các phương thức để thực hiện điều này trong MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 và Oracle (sau đây được sao chép từ liên kết đó):

Chọn một hàng ngẫu nhiên với MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Chọn một hàng ngẫu nhiên với PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Chọn một hàng ngẫu nhiên với Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Chọn một hàng ngẫu nhiên với IBM DB2

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

Chọn một bản ghi ngẫu nhiên với Oracle:

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

30
-1 để dựa vào order by rand()hoặc tương đương trong tất cả các dbs: |. cũng được đề cập ở đây .
AD7six

20
Mười năm trước, một số người nói rằng sử dụng ORDER BY RAND()là sai ...
trejder

ĐẶT HÀNG THEO NEWID () dường như chậm hơn rõ rệt trên SQL Server. Truy vấn của tôi trông giống như: chọn 1000 C.CustomerId, CL.LoginName hàng đầu từ Khách hàng C tham gia bên trong LinkedAccount LA trên C.CustomerId = LA.CustomerId tham gia bên trong CustomerLogin CL trên C.CustomerId = CL.CustomerId nhóm của C.CustomerId, CL. Tên đăng nhập có số lượng (*)> 1 đơn hàng theo NEWID () Xóa dòng "thứ tự theo NEWID ()" trả về kết quả nhanh hơn nhiều.
Ben Power

3
Đối với SQLite, sử dụng hàm RANDOM ().
Slam

10
Những giải pháp này không mở rộng. Họ đang O(n)nsố lượng hồ sơ trong bảng. Hãy tưởng tượng bạn có 1 triệu hồ sơ, bạn có thực sự muốn tạo 1 triệu số ngẫu nhiên hoặc id duy nhất không? Tôi muốn sử dụng COUNT()và liên quan đến điều đó trong một LIMITbiểu thức mới với một số ngẫu nhiên duy nhất.
Christian Hujer

174

Các giải pháp như Kẻ thù:

SELECT * FROM table ORDER BY RAND() LIMIT 1

hoạt động, nhưng họ cần quét tuần tự tất cả các bảng (vì giá trị ngẫu nhiên được liên kết với mỗi hàng cần được tính toán - sao cho có thể xác định giá trị nhỏ nhất), có thể khá chậm đối với các bảng có kích thước trung bình. Đề xuất của tôi sẽ là sử dụng một số loại cột số được lập chỉ mục (nhiều bảng có các khóa này làm khóa chính) và sau đó viết một cái gì đó như:

SELECT * FROM table WHERE num_value >= RAND() * 
    ( SELECT MAX (num_value ) FROM table ) 
ORDER BY num_value LIMIT 1

Điều này hoạt động trong thời gian logarit, bất kể kích thước bảng, nếu num_valueđược lập chỉ mục. Một cảnh báo: điều này giả định num_valueđược phân bổ đều trong phạm vi 0..MAX(num_value). Nếu tập dữ liệu của bạn sai lệch mạnh mẽ với giả định này, bạn sẽ nhận được kết quả sai lệch (một số hàng sẽ xuất hiện thường xuyên hơn các hàng khác).


8
Gợi ý thứ hai không phải là ngẫu nhiên. Bạn không thể dự đoán hàng sẽ được chọn, nhưng nếu bạn phải đặt cược, bạn sẽ đặt cược vào hàng thứ hai. Và bạn sẽ không bao giờ đặt cược vào hàng cuối cùng, ít có khả năng được chọn bất cứ thứ gì là phân phối num_value của bạn và bàn của bạn lớn như thế nào.
đua Etienne

1
Tôi biết rằng thường các hàm RAND () không có chất lượng rất cao, nhưng ngoài ra bạn có thể giải thích rõ tại sao lựa chọn sẽ không ngẫu nhiên không?
Grey Panther

13
Cái đầu tiên là SAI trong SQL Server. Hàm RAND () chỉ được gọi một lần cho mỗi truy vấn chứ không phải một lần trên mỗi hàng. Vì vậy, nó luôn luôn chọn hàng đầu tiên (thử nó).
Jeff Walker Code Ranger

3
Cái thứ hai cũng giả định rằng tất cả các hàng được tính: có thể nó sẽ chọn một hàng đã bị xóa.
Sam Ruither

3
@ Sam. Thực tế, num_value> = RAND () ... giới hạn 1 đảm bảo rằng các hàng trống sẽ bị bỏ qua cho đến khi tìm thấy hàng hiện tại.
ghord

62

Tôi không biết hiệu quả của nó như thế nào, nhưng tôi đã sử dụng nó trước đây:

SELECT TOP 1 * FROM MyTable ORDER BY newid()

Vì GUID khá ngẫu nhiên, nên việc đặt hàng có nghĩa là bạn nhận được một hàng ngẫu nhiên.


1
Tôi đang sử dụng máy chủ MS SQL, CHỌN TOP 1 * TỪ some_table_name ĐẶT HÀNG THEO NEWID () hoạt động rất tốt cho tôi, cảm ơn các bạn đã tư vấn!

Điều đó hoàn toàn giống vớiORDER BY RAND() LIMIT 1
Ken Bloom

6
Đây cũng là cơ sở dữ liệu rất cụ thể vì nó sử dụng TOP 1newid().
Xám

12
Đây là một ý tưởng tồi. Phương pháp này sẽ không sử dụng một chỉ mục trừ khi mỗi cột được lập chỉ mục một cách ngẫu nhiên. Bảng có 100 triệu bản ghi có thể mất một thời gian rất dài để có được một bản ghi.
Chuyển

1
@Switch và bạn sẽ đề xuất giải pháp nào?
Akmal Salikhov

31
ORDER BY NEWID()

nhận 7.4 milliseconds

WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table)

mất 0.0065 milliseconds!

Tôi chắc chắn sẽ đi với phương pháp sau.


2
Tùy chọn thứ hai sẽ không chọn hàng cuối cùng. Tôi không biết tại sao - chỉ cần chỉ ra.
Voldemort

7
@Voldemort: rand()trả về số dấu phẩy động ntrong đó 0 < n < 1. Giả sử num_valuelà một số nguyên, giá trị trả về của rand() * max(num_value)cũng sẽ bị ép buộc thành một số nguyên, do đó cắt bất cứ thứ gì sau dấu thập phân. Do đó, rand() * max(num_value)sẽ luôn luôn ít hơn max(num_value), đó là lý do tại sao hàng cuối cùng sẽ không bao giờ được chọn.
Ian Kemp

Tôi sẽ không hiệu quả nếu dữ liệu của tôi bị xóa thường xuyên - nếu tôi tìm thấy một khoảng trống, tôi sẽ phải chạy lại toàn bộ truy vấn.
Loic Coenen

1
@IanKemp Câu hỏi ngu ngốc, vậy thì tại sao không sử dụng CHỌN MAX (num_value) + 1 ?? Vì rand (hoặc RANDOM trong hầu hết các trường hợp) trả về [0,1), bạn sẽ nhận được đầy đủ các giá trị. Ngoài ra, yeah, bạn đã đúng, phải sửa một truy vấn.
tekHedd

13

Bạn đã không nói máy chủ nào bạn đang sử dụng. Trong các phiên bản cũ hơn của SQL Server, bạn có thể sử dụng điều này:

select top 1 * from mytable order by newid()

Trong SQL Server 2005 trở lên, bạn có thể sử dụng TABLESAMPLEđể lấy một mẫu ngẫu nhiên có thể lặp lại:

SELECT FirstName, LastName
FROM Contact 
TABLESAMPLE (1 ROWS) ;

9
MSDN cho biết newid () được ưa thích hơn mẫu cho kết quả thực sự ngẫu nhiên: msdn.microsoft.com/en-us/l
Andrew Hedges

7
@Andrew Hedges: ĐẶT HÀNG THEO NEWID () quá tốn kém
Andrei Rînea

10

Đối với máy chủ SQL

newid () / order by sẽ hoạt động, nhưng sẽ rất tốn kém cho các tập kết quả lớn vì nó phải tạo id cho mỗi hàng, sau đó sắp xếp chúng.

TABLESAMPLE () tốt từ quan điểm hiệu suất, nhưng bạn sẽ nhận được kết quả (tất cả các hàng trên một trang sẽ được trả về).

Để có một mẫu ngẫu nhiên thực sự tốt hơn, cách tốt nhất là lọc ra các hàng ngẫu nhiên. Tôi đã tìm thấy mẫu mã sau đây trong bài viết trực tuyến Giới hạn bộ bài viết của SQL Server bằng cách sử dụng TABLESAMPLE :

Nếu bạn thực sự muốn một mẫu ngẫu nhiên của các hàng riêng lẻ, hãy sửa đổi truy vấn của bạn để lọc ra các hàng ngẫu nhiên, thay vì sử dụng TABLESAMPLE. Ví dụ: truy vấn sau sử dụng hàm NEWID để trả về khoảng một phần trăm các hàng của bảng Sales.SalesOrderDetail:

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float)
              / CAST (0x7fffffff AS int)

Cột SalesOrderID được bao gồm trong biểu thức CHECKSUM để NEWID () đánh giá một lần trên mỗi hàng để đạt được lấy mẫu trên cơ sở mỗi hàng. Biểu thức CAST (CHECKSUM (NEWID (), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int) ước tính giá trị float ngẫu nhiên trong khoảng từ 0 đến 1.

Khi chạy với bảng có 1.000.000 hàng, đây là kết quả của tôi:

SET STATISTICS TIME ON
SET STATISTICS IO ON

/* newid()
   rows returned: 10000
   logical reads: 3359
   CPU time: 3312 ms
   elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()

/* TABLESAMPLE
   rows returned: 9269 (varies)
   logical reads: 32
   CPU time: 0 ms
   elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)

/* Filter
   rows returned: 9994 (varies)
   logical reads: 3359
   CPU time: 641 ms
   elapsed time: 627 ms
*/    
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float) 
              / CAST (0x7fffffff AS int)

SET STATISTICS IO OFF
SET STATISTICS TIME OFF

Nếu bạn có thể thoát khỏi việc sử dụng TABLESAMPLE, nó sẽ mang lại cho bạn hiệu suất tốt nhất. Nếu không, sử dụng phương thức newid () / filter. newid () / order by nên là giải pháp cuối cùng nếu bạn có tập kết quả lớn.


4

Nếu có thể, hãy sử dụng các câu lệnh được lưu trữ để tránh sự kém hiệu quả của cả hai chỉ mục trên RND () và tạo trường số bản ghi.

CHUẨN BỊ RandomRecord TỪ "CHỌN * TỪ GIỚI HẠN bảng ?, 1";
SET @ n = FLOOR (RAND () * (CHỌN COUNT (*) TỪ bảng));
EXECUTE RandomRecord SỬ DỤNG @n;

Giải pháp này cũng đảm nhiệm việc trả về các hàng ngẫu nhiên khi giá trị số được lập chỉ mục được sử dụng trong mệnh đề where ở trên không được phân phối bằng nhau; vì vậy ngay cả khi mất gần như cùng một thời gian (không đổi) khi sử dụng id_value> = RAND () * MAX (id_value), thì vẫn tốt hơn.
guido

Theo như tôi có thể nói điều này không chạy trong thời gian liên tục, nó chạy trong thời gian tuyến tính. Trong trường hợp xấu nhất, @n bằng số lượng hàng trong bảng và "CHỌN * TỪ GIỚI HẠN bảng ?, 1" đánh giá @n - 1 hàng cho đến khi đến hàng cuối cùng.
Andres Riofrio

3

Cách tốt nhất là đặt một giá trị ngẫu nhiên vào một cột mới chỉ cho mục đích đó và sử dụng một cái gì đó như thế này (mã giả + SQL):

randomNo = random()
execSql("SELECT TOP 1 * FROM MyTable WHERE MyTable.Randomness > $randomNo")

Đây là giải pháp được sử dụng bởi mã MediaWiki. Tất nhiên, có một số sai lệch so với các giá trị nhỏ hơn, nhưng họ thấy rằng nó đủ để bọc giá trị ngẫu nhiên quanh 0 khi không có hàng nào được tìm nạp.

giải pháp newid () có thể yêu cầu quét toàn bộ bảng để mỗi hàng có thể được chỉ định một hướng dẫn mới, sẽ ít hiệu quả hơn nhiều.

Giải pháp rand () hoàn toàn không thể hoạt động (ví dụ với MSSQL) vì hàm này sẽ được đánh giá chỉ một lần và mỗi hàng sẽ được gán cùng một số "ngẫu nhiên".


1
Bao bọc xung quanh khi bạn nhận được 0 kết quả cung cấp một mẫu ngẫu nhiên có thể chứng minh được (không chỉ là "đủ tốt"). Giải pháp này gần như mở rộng cho các truy vấn nhiều hàng (nghĩ rằng "xáo trộn bên"). Vấn đề là kết quả có xu hướng được chọn trong cùng một nhóm nhiều lần. Để giải quyết vấn đề này, bạn sẽ cần phân phối lại các số ngẫu nhiên bạn vừa sử dụng. Bạn có thể gian lận bằng cách theo dõi ngẫu nhiênKhông và đặt nó ở mức tối đa (tính ngẫu nhiên) từ kết quả, nhưng sau đó p (hàng i trên truy vấn 1 VÀ hàng i trên truy vấn 2) == 0, không công bằng. Hãy để tôi làm một số phép toán, và tôi sẽ quay lại với bạn với một kế hoạch thực sự công bằng.
alsuren

3

Đối với SQL Server 2005 và 2008, nếu chúng tôi muốn một mẫu ngẫu nhiên các hàng riêng lẻ (từ Sách trực tuyến ):

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)

3

Được sử dụng RAND (), vì nó không được khuyến khích , bạn có thể chỉ cần lấy ID tối đa (= Max):

SELECT MAX(ID) FROM TABLE;

nhận ngẫu nhiên giữa 1..Max (= My_Generated_Random)

My_Generated_Random = rand_in_your_programming_lang_function(1..Max);

và sau đó chạy SQL này:

SELECT ID FROM TABLE WHERE ID >= My_Generated_Random ORDER BY ID LIMIT 1

Lưu ý rằng nó sẽ kiểm tra bất kỳ hàng nào có Id là THIẾT BỊ hoặc CAO hơn giá trị đã chọn. Bạn cũng có thể tìm kiếm hàng trong bảng và nhận ID bằng hoặc thấp hơn My_Generated_Random, sau đó sửa đổi truy vấn như sau:

SELECT ID FROM TABLE WHERE ID <= My_Generated_Random ORDER BY ID DESC LIMIT 1

Điều gì sẽ xảy ra nếu ID ngẫu nhiên được tạo không còn tồn tại trong bảng nữa? Các hàng bị xóa hoặc thụ động mà bạn không muốn hiển thị cho người dùng sẽ gây rắc rối.
Ebleme

Không có gì. Bạn nhận được số CLOSEST, không chính xác, số id. Nếu bạn coi id = 1 bị xóa, hãy trao đổi 1 với mức tối thiểu.
forsberg

2

Như đã chỉ ra trong nhận xét của @ BillKarwin về câu trả lời của @ cnu ...

Khi kết hợp với GIỚI HẠN, tôi đã thấy rằng nó hoạt động tốt hơn nhiều (ít nhất là với PostgreQuery 9.1) để THAM GIA với một thứ tự ngẫu nhiên thay vì đặt trực tiếp các hàng thực tế: vd

SELECT * FROM tbl_post AS t
JOIN ...
JOIN ( SELECT id, CAST(-2147483648 * RANDOM() AS integer) AS rand
       FROM tbl_post
       WHERE create_time >= 1349928000
     ) r ON r.id = t.id
WHERE create_time >= 1349928000 AND ...
ORDER BY r.rand
LIMIT 100

Chỉ cần đảm bảo rằng 'r' tạo ra giá trị 'rand' cho mọi giá trị khóa có thể có trong truy vấn phức tạp được nối với nó nhưng vẫn giới hạn số lượng hàng 'r' nếu có thể.

CAST as Integer đặc biệt hữu ích cho PostgreQuery 9.2, có tối ưu hóa sắp xếp cụ thể cho các kiểu nổi chính xác và số nguyên.


1

Hầu hết các giải pháp ở đây nhằm tránh việc sắp xếp, nhưng chúng vẫn cần thực hiện quét tuần tự trên một bảng.

Cũng có một cách để tránh quét tuần tự bằng cách chuyển sang quét chỉ mục. Nếu bạn biết giá trị chỉ mục của hàng ngẫu nhiên, bạn có thể nhận được kết quả gần như ngay lập tức. Vấn đề là - làm thế nào để đoán một giá trị chỉ số.

Giải pháp sau đây hoạt động trên PostgreSQL 8.4:

explain analyze select * from cms_refs where rec_id in 
  (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
   from generate_series(1,10))
  limit 1;

Tôi ở trên giải pháp bạn đoán 10 giá trị chỉ số ngẫu nhiên khác nhau từ phạm vi 0 .. [giá trị cuối cùng của id].

Số 10 là tùy ý - bạn có thể sử dụng 100 hoặc 1000 vì nó (đáng kinh ngạc) không ảnh hưởng lớn đến thời gian phản hồi.

Cũng có một vấn đề - nếu bạn có id thưa thớt bạn có thể bỏ lỡ . Giải pháp là có một kế hoạch dự phòng :) Trong trường hợp này là một thứ tự thuần túy theo truy vấn ngẫu nhiên (). Khi id kết hợp trông như thế này:

explain analyze select * from cms_refs where rec_id in 
    (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
     from generate_series(1,10))
    union all (select * from cms_refs order by random() limit 1)
    limit 1;

Không phải mệnh đề TẤT CẢ liên minh . Trong trường hợp này nếu phần đầu tiên trả về bất kỳ dữ liệu nào thì phần thứ hai KHÔNG BAO GIỜ được thực thi!


1

Cuối cùng, nhưng đã đến đây thông qua Google, vì lợi ích của hậu thế, tôi sẽ thêm một giải pháp thay thế.

Một cách tiếp cận khác là sử dụng TOP hai lần, với các đơn đặt hàng xen kẽ. Tôi không biết đó có phải là "SQL thuần" hay không, bởi vì nó sử dụng một biến trong TOP, nhưng nó hoạt động trong SQL Server 2008. Đây là một ví dụ tôi sử dụng đối với một bảng từ trong từ điển, nếu tôi muốn một từ ngẫu nhiên.

SELECT TOP 1
  word
FROM (
  SELECT TOP(@idx)
    word 
  FROM
    dbo.DictionaryAbridged WITH(NOLOCK)
  ORDER BY
    word DESC
) AS D
ORDER BY
  word ASC

Tất nhiên, @idx là một số nguyên được tạo ngẫu nhiên, nằm trong khoảng từ 1 đến COUNT (*) trên bảng đích. Nếu cột của bạn được lập chỉ mục, bạn cũng sẽ được hưởng lợi từ nó. Một ưu điểm khác là bạn có thể sử dụng nó trong một hàm, vì NEWID () không được phép.

Cuối cùng, truy vấn trên chạy trong khoảng 1/10 thời gian thực hiện của NEWID () - loại truy vấn trên cùng một bảng. YYMV.


1

Bạn cũng có thể thử sử dụng new id()chức năng.

Chỉ cần viết một truy vấn của bạn và sử dụng thứ tự theo new id()chức năng. Nó khá ngẫu nhiên.


1

Để MySQL có được bản ghi ngẫu nhiên

 SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1

Chi tiết hơn http://jan.kneschke.de/projects/mysql/order-by-rand/


Sau khi thử nghiệm nhiều câu trả lời tôi tin rằng đây là câu trả lời hay nhất. Nó dường như là nhanh và chọn một số ngẫu nhiên tốt mỗi lần. Có vẻ như tương tự như đề xuất thứ hai của @GreyPanther ở trên, nhưng câu trả lời này chọn nhiều số ngẫu nhiên hơn.
Jeff Baker

1

Chưa thấy biến thể này trong các câu trả lời. Tôi đã có một ràng buộc bổ sung khi tôi cần, được cung cấp một hạt giống ban đầu, để chọn cùng một bộ hàng mỗi lần.

Đối với MS SQL:

Ví dụ tối thiểu:

select top 10 percent *
from table_name
order by rand(checksum(*))

Thời gian thực hiện chuẩn hóa: 1,00

Ví dụ về NewId ():

select top 10 percent *
from table_name
order by newid()

Thời gian thực hiện chuẩn hóa: 1,02

NewId() chậm hơn đáng kể so với rand(checksum(*)) , vì vậy bạn có thể không muốn sử dụng nó cho các bộ hồ sơ lớn.

Lựa chọn với Seed ban đầu:

declare @seed int
set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */

select top 10 percent *
from table_name
order by rand(checksum(*) % seed) /* any other math function here */

Nếu bạn cần chọn cùng một bộ đã cho một hạt giống, điều này dường như hoạt động.


1

Trong MSSQL (được thử nghiệm vào ngày 11.0.5569) bằng cách sử dụng

SELECT TOP 100 * FROM employee ORDER BY CRYPT_GEN_RANDOM(10)

nhanh hơn đáng kể so với

SELECT TOP 100 * FROM employee ORDER BY NEWID()

1

Trong SQL Server, bạn có thể kết hợp TABLESAMPLE với NEWID () để có được tính ngẫu nhiên khá tốt và vẫn có tốc độ. Điều này đặc biệt hữu ích nếu bạn thực sự chỉ muốn 1 hoặc một số lượng nhỏ các hàng.

SELECT TOP 1 * FROM [table] 
TABLESAMPLE (500 ROWS) 
ORDER BY NEWID()

1

Với SQL Server 2012+, bạn có thể sử dụng truy vấn OFFSET FETCH để thực hiện việc này cho một hàng ngẫu nhiên

select  * from MyTable ORDER BY id OFFSET n ROW FETCH NEXT 1 ROWS ONLY

trong đó id là một cột định danh và n là hàng bạn muốn - được tính là một số ngẫu nhiên trong khoảng từ 0 đến đếm () - 1 của bảng (bù 0 là hàng đầu tiên sau tất cả)

Điều này hoạt động với các lỗ trong dữ liệu bảng, miễn là bạn có một chỉ mục để làm việc với mệnh đề ORDER BY. Nó cũng rất tốt cho sự ngẫu nhiên - khi bạn làm việc mà tự mình vượt qua nhưng những khúc mắc trong các phương pháp khác không có mặt. Ngoài ra, hiệu suất khá tốt, trên một tập dữ liệu nhỏ hơn, nó vẫn giữ tốt, mặc dù tôi đã không thử các bài kiểm tra hiệu suất nghiêm trọng đối với vài triệu hàng.


0
 SELECT * FROM table ORDER BY RAND() LIMIT 1

Mười năm trước (2005) một số anh chàng nói rằng sử dụng ORDER BY RAND()là sai ...
trejder

0

Tôi phải đồng ý với CD-MaN: Sử dụng "ORDER BY RAND ()" sẽ hoạt động tốt cho các bảng nhỏ hoặc khi bạn thực hiện CHỌN chỉ một vài lần.

Tôi cũng sử dụng kỹ thuật "num_value> = RAND () * ..." và nếu tôi thực sự muốn có kết quả ngẫu nhiên, tôi có một cột "ngẫu nhiên" đặc biệt trong bảng mà tôi cập nhật mỗi ngày một lần. Lần chạy CẬP NHẬT duy nhất đó sẽ mất một chút thời gian (đặc biệt là vì bạn sẽ phải có một chỉ mục trên cột đó), nhưng nó nhanh hơn nhiều so với việc tạo các số ngẫu nhiên cho mỗi hàng mỗi khi lựa chọn được chạy.


0

Hãy cẩn thận vì TableSample không thực sự trả về một mẫu hàng ngẫu nhiên. Nó hướng truy vấn của bạn để xem xét một mẫu ngẫu nhiên của các trang 8KB tạo nên hàng của bạn. Sau đó, truy vấn của bạn được thực hiện đối với dữ liệu có trong các trang này. Do cách dữ liệu có thể được nhóm trên các trang này (thứ tự chèn, v.v.), điều này có thể dẫn đến dữ liệu không thực sự là một mẫu ngẫu nhiên.

Xem: http://www.mssqltips.com/tip.asp?tip=1308

Trang MSDN cho TableSample này bao gồm một ví dụ về cách tạo một mẫu dữ liệu ngẫu nhiên thực tế.

http://msdn.microsoft.com/en-us/l Library / ms189108.aspx


0

Có vẻ như nhiều ý tưởng được liệt kê vẫn sử dụng đặt hàng

Tuy nhiên, nếu bạn sử dụng bảng tạm thời, bạn có thể chỉ định một chỉ mục ngẫu nhiên (giống như nhiều giải pháp đã đề xuất), sau đó lấy bảng đầu tiên lớn hơn số tùy ý trong khoảng từ 0 đến 1.

Ví dụ (đối với DB2):

WITH TEMP AS (
SELECT COMLUMN, RAND() AS IDX FROM TABLE)
SELECT COLUMN FROM TABLE WHERE IDX > .5
FETCH FIRST 1 ROW ONLY

2
Sau khi xem xét giải pháp này, tôi đã tìm thấy một lỗ hổng cơ bản trong logic của mình. Điều này sẽ liên tục trả về các giá trị thiết lập nhỏ tương tự, ở gần đầu bảng, vì tôi cho rằng nếu có sự phân phối đồng đều giữa 0 và 1, có 50% khả năng hàng đầu tiên sẽ đáp ứng tiêu chí đó.
DAVID


0

Có giải pháp tốt hơn cho Oracle thay vì sử dụng dbms_random.value, trong khi nó yêu cầu quét toàn bộ để đặt hàng theo dbms_random.value và nó khá chậm đối với các bảng lớn.

Sử dụng cái này thay thế:

SELECT *
FROM employee sample(1)
WHERE rownum=1

0

Đối với Firebird:

Select FIRST 1 column from table ORDER BY RAND()

0

Đối với SQL Server 2005 trở lên, mở rộng câu trả lời của @ GreyPanther cho các trường hợp khi num_valuekhông có giá trị liên tục. Điều này cũng hoạt động đối với các trường hợp khi chúng ta không phân phối các bộ dữ liệu và khi đó num_valuekhông phải là một số mà là một định danh duy nhất.

WITH CTE_Table (SelRow, num_value) 
AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY ID) AS SelRow, num_value FROM table
) 

SELECT * FROM table Where num_value = ( 
    SELECT TOP 1 num_value FROM CTE_Table  WHERE SelRow >= RAND() * (SELECT MAX(SelRow) FROM CTE_Table)
)

-1

Chức năng ngẫu nhiên từ sql có thể giúp đỡ. Ngoài ra nếu bạn muốn giới hạn chỉ một hàng, chỉ cần thêm nó vào cuối.

SELECT column FROM table
ORDER BY RAND()
LIMIT 1
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.