Як випадково отримати записи з бази даних oracle?


82

Мені потрібно довільно вибирати рядки з БД Oracle.

Приклад: Припустимо таблицю зі 100 рядками, як я можу випадковим чином повернути 20 із цих записів із усіх 100 рядків.

Відповіді:


111
SELECT *
FROM   (
    SELECT *
    FROM   table
    ORDER BY DBMS_RANDOM.RANDOM)
WHERE  rownum < 21;

1
Побий мене. Однак буде вибрано лише перші 20 рядків із таблиці та впорядковано їх випадковим чином.
— Nishant Sharma

10
Ви повинні пам’ятати, що це дуже важка операція на великих таблицях, оскільки вона спочатку призначає КОЖНОМУ рядку випадкове число, потім сортує це значення, а потім бере з нього деякі записи.
— Roeland Van Heddegem

11
@NishantSharma, рядки рандомізовані, потім обмежені - ваш коментар неправильний.
— Simon MᶜKenzie

6
Цей підхід ДУЖЕ повільний
— Еван Кроске

1
@JonBetts, я думаю , що зразок набагато швидше і ефективніше використання ресурсів: stackoverflow.com/a/9920431/156787
— Еван Kroske

50

Гарантовано, що SAMPLE () не дасть вам рівно 20 рядків, але може бути підходящим (і може працювати значно краще, ніж повний запит + сортування за випадковим для великих таблиць):

SELECT *
FROM   table SAMPLE(20);

Примітка: 20тут наведено приблизний відсоток, а не кількість бажаних рядків. У цьому випадку, оскільки у вас 100 рядків, для отримання приблизно 20 рядків ви просите 20% вибірки.


1
зразок швидкий, але, здається, не дуже випадковий. записи вгорі / на початку таблиці мають перевагу.
— craigrs84

1
це станеться, якщо ви зупините запит до того, як він пройде через всю таблицю.
— Джеффрі Кемп,

2
Вибачте, я допустив помилку, ваша публікація чудова, а результати розподілені порівну. Це коли ви додаєте "where rownum <= 20" у поєднанні з вибіркою (20), дані починають ставати менш випадковими.
— craigrs84

14
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;

Це більш ефективно, оскільки не потрібно сортувати таблицю.


7
Зупинка вибірки після 20 рядків призведе до випадкових результатів (рядки, знайдені раніше в таблиці, повертатимуться набагато частіше, ніж пізніші). Крім того, не гарантовано повернення 20 рядків.
— Джеффрі Кемп,

10
SELECT column FROM
( SELECT column, dbms_random.value FROM table ORDER BY 2 )
where rownum <= 20;

4

Для випадкового вибору 20 рядків, я думаю, вам було б краще вибрати довільно впорядковану партію та вибрати перші 20 із цього набору.

Щось на зразок:

Select *
  from (select *
          from table
         order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
 where rownum < 21;

Найкраще використовувати для невеликих таблиць, щоб уникнути виділення великих шматків даних лише для того, щоб відкинути більшу їх частину.


3

Таким чином, було введено два шляхи

1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function

Перший спосіб має перевагу в «ПРАВИЛЬНІСТІ», що означає, що ви ніколи не зможете отримати результат, якщо він насправді існує, тоді як у другому способі ви можете не отримати результату, навіть якщо він має випадки, що задовольняють умову запиту, оскільки інформація зменшується під час вибірки.

Другий спосіб має перевагу в "ЕФЕКТИВНОСТІ", що означає, що ви швидше отримаєте результат і полегшите свою базу даних. Я отримав попередження від DBA, що мій запит, що використовує перший спосіб, дає навантаження до бази даних

Ви можете обрати один із двох способів відповідно до своїх інтересів!


1

У випадку величезних таблиць стандартний спосіб сортування за 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
      )
);

0

Ось як вибрати випадкову вибірку з кожної групи:

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;

Я не впевнений, наскільки це ефективно, але якщо у вас багато категорій та підкатегорій, це, здається, добре виконує роботу.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.