Tôi cần chọn các hàng ngẫu nhiên từ Oracle DB.
Ví dụ: Giả sử một bảng có 100 hàng, làm cách nào để tôi có thể trả về ngẫu nhiên 20 bản ghi đó từ toàn bộ 100 hàng.
Câu trả lời:
SELECT *
FROM (
SELECT *
FROM table
ORDER BY DBMS_RANDOM.RANDOM)
WHERE rownum < 21;
SAMPLE () không được đảm bảo cung cấp cho bạn chính xác 20 hàng, nhưng có thể phù hợp (và có thể hoạt động tốt hơn đáng kể so với truy vấn đầy đủ + sắp xếp theo ngẫu nhiên cho các bảng lớn):
SELECT *
FROM table SAMPLE(20);
Lưu ý: 20
đây là tỷ lệ phần trăm gần đúng, không phải số hàng mong muốn. Trong trường hợp này, vì bạn có 100 hàng, nên để có được khoảng 20 hàng, bạn yêu cầu mẫu 20%.
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;
Điều này hiệu quả hơn vì nó không cần phải sắp xếp Bảng.
Để chọn ngẫu nhiên 20 hàng, tôi nghĩ tốt hơn hết bạn nên chọn rất nhiều trong số chúng được sắp xếp ngẫu nhiên và chọn 20 hàng đầu tiên của bộ đó.
Cái gì đó như:
Select *
from (select *
from table
order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
where rownum < 21;
Tốt nhất được sử dụng cho các bảng nhỏ để tránh chọn các khối dữ liệu lớn chỉ để loại bỏ hầu hết.
Tóm lại, hai cách đã được giới thiệu
1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function
Cách đầu tiên có lợi thế trong 'CORRECTNESS' có nghĩa là bạn sẽ không bao giờ nhận được kết quả nếu nó thực sự tồn tại, trong khi theo cách thứ hai, bạn có thể không nhận được kết quả mặc dù nó có các trường hợp thỏa mãn điều kiện truy vấn vì thông tin bị giảm trong quá trình lấy mẫu.
Cách thứ hai có lợi thế về 'HIỆU QUẢ' có nghĩa là bạn sẽ nhận được kết quả nhanh hơn và tải nhẹ cho cơ sở dữ liệu của bạn. Tôi đã nhận được một cảnh báo từ DBA rằng truy vấn của tôi bằng cách đầu tiên cung cấp tải cho cơ sở dữ liệu
Bạn có thể chọn một trong hai cách tùy theo sở thích của mình!
Trong trường hợp các bảng lớn, cách sắp xếp theo dbms_random.value không hiệu quả vì bạn cần quét toàn bộ bảng và dbms_random.value là chức năng khá chậm và yêu cầu chuyển đổi ngữ cảnh. Đối với những trường hợp như vậy, có 3 phương pháp bổ sung:
1: Sử dụng sample
mệnh đề:
ví dụ:
select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only
tức là lấy 1% của tất cả các khối, sau đó sắp xếp chúng ngẫu nhiên và chỉ trả về 1 hàng.
2: nếu bạn có chỉ mục / khóa chính trên cột có phân phối chuẩn , bạn có thể nhận giá trị tối thiểu và tối đa, nhận giá trị ngẫu nhiên trong phạm vi này và nhận hàng đầu tiên có giá trị lớn hơn hoặc bằng giá trị được tạo ngẫu nhiên đó.
Thí dụ:
--big table with 1 mln rows with primary key on ID with normal distribution:
Create table s1(id primary key,padding) as
select level, rpad('x',100,'x')
from dual
connect by level<=1e6;
select *
from s1
where id>=(select
dbms_random.value(
(select min(id) from s1),
(select max(id) from s1)
)
from dual)
order by id
fetch first 1 rows only;
3: lấy khối bảng ngẫu nhiên, tạo rowid và lấy hàng từ bảng bởi rowid này :
select *
from s1
where rowid = (
select
DBMS_ROWID.ROWID_CREATE (
1,
objd,
file#,
block#,
1)
from
(
select/*+ rule */ file#,block#,objd
from v$bh b
where b.objd in (select o.data_object_id from user_objects o where object_name='S1' /* table_name */)
order by dbms_random.value
fetch first 1 rows only
)
);
Đây là cách chọn một mẫu ngẫu nhiên từ mỗi nhóm:
SELECT GROUPING_COLUMN,
MIN (COLUMN_NAME) KEEP (DENSE_RANK FIRST ORDER BY DBMS_RANDOM.VALUE)
AS RANDOM_SAMPLE
FROM TABLE_NAME
GROUP BY GROUPING_COLUMN
ORDER BY GROUPING_COLUMN;
Tôi không chắc nó hiệu quả như thế nào, nhưng nếu bạn có nhiều danh mục và tiểu mục, điều này có vẻ hoạt động tốt.
bàn
SELECT * FROM
(
SELECT column_name FROM table_name
ORDER BY dbms_random.value
)
WHERE rownum = 1;