Як випадково отримати записи з бази даних 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.