Мені потрібно довільно вибирати рядки з БД Oracle.
Приклад: Припустимо таблицю зі 100 рядками, як я можу випадковим чином повернути 20 із цих записів із усіх 100 рядків.
Відповіді:
SELECT *
FROM (
SELECT *
FROM table
ORDER BY DBMS_RANDOM.RANDOM)
WHERE rownum < 21;
Гарантовано, що SAMPLE () не дасть вам рівно 20 рядків, але може бути підходящим (і може працювати значно краще, ніж повний запит + сортування за випадковим для великих таблиць):
SELECT *
FROM table SAMPLE(20);
Примітка: 20
тут наведено приблизний відсоток, а не кількість бажаних рядків. У цьому випадку, оскільки у вас 100 рядків, для отримання приблизно 20 рядків ви просите 20% вибірки.
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;
Це більш ефективно, оскільки не потрібно сортувати таблицю.
Для випадкового вибору 20 рядків, я думаю, вам було б краще вибрати довільно впорядковану партію та вибрати перші 20 із цього набору.
Щось на зразок:
Select *
from (select *
from table
order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
where rownum < 21;
Найкраще використовувати для невеликих таблиць, щоб уникнути виділення великих шматків даних лише для того, щоб відкинути більшу їх частину.
Таким чином, було введено два шляхи
1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function
Перший спосіб має перевагу в «ПРАВИЛЬНІСТІ», що означає, що ви ніколи не зможете отримати результат, якщо він насправді існує, тоді як у другому способі ви можете не отримати результату, навіть якщо він має випадки, що задовольняють умову запиту, оскільки інформація зменшується під час вибірки.
Другий спосіб має перевагу в "ЕФЕКТИВНОСТІ", що означає, що ви швидше отримаєте результат і полегшите свою базу даних. Я отримав попередження від DBA, що мій запит, що використовує перший спосіб, дає навантаження до бази даних
Ви можете обрати один із двох способів відповідно до своїх інтересів!
У випадку величезних таблиць стандартний спосіб сортування за dbms_random.value неефективний, оскільки вам потрібно просканувати всю таблицю, а dbms_random.value є досить повільною функцією і вимагає перемикання контексту. Для таких випадків існує 3 додаткові методи:
1: Використовуйте sample
речення:
наприклад:
select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only
тобто отримати 1% усіх блоків, потім відсортувати їх випадковим чином і повернути лише 1 рядок.
2: якщо у вас є індекс / первинний ключ у стовпці з нормальним розподілом , ви можете отримати значення min та max, отримати випадкове значення в цьому діапазоні та отримати перший рядок із значенням, більшим або рівним цьому випадково сформованому значенню.
Приклад:
--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: отримати випадковий блок таблиці, згенерувати rowid і отримати рядок з таблиці за цим rowid :
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
)
);
Ось як вибрати випадкову вибірку з кожної групи:
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;
Я не впевнений, наскільки це ефективно, але якщо у вас багато категорій та підкатегорій, це, здається, добре виконує роботу.
таблиця
SELECT * FROM
(
SELECT column_name FROM table_name
ORDER BY dbms_random.value
)
WHERE rownum = 1;