Случайный выбор строки - PullRequest
1 голос
/ 12 июля 2020

У меня есть таблица s1, в которой 3 строки. Как я могу СЛУЧАЙНО выбрать строку из s1 и ВСТАВИТЬ ее соответствующее значение в d1.

Мне не нужно жестко закодированное решение. Можно ли использовать ROWNUM () тогда dbms_random? Скажем, мне нужно 10 строк в d1.

Приветствуется пример.

Create table s1(
val NUMBER(4)
);

 INSERT into s1
(val) VALUES (30);

 INSERT into s1
 (val) VALUES (40);

 INSERT into s1
 (val) VALUES (50);

Create table d1(
val NUMBER(4)
 );

Ответы [ 2 ]

1 голос
/ 13 июля 2020

В случае огромных таблиц стандартный способ с сортировкой по dbms_random.value неэффективен, потому что вам нужно сканировать всю таблицу, а dbms_random.value - довольно медленная функция и требует переключения контекста. Для таких случаев есть 2 хорошо известных метода:

  1. Использование sample clause:

например:

select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only

ie получить 1% всех блоков, затем отсортировать их случайным образом и вернуть только 1 строку.

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

Пример:

--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
      )
);
1 голос
/ 12 июля 2020

Вы можете отсортировать по случайному значению и выбрать одну строку:

insert into d1 (val)
    select val
    from (select s1.*
          from s1
          order by dbms_random.value
         ) s1
    where rownum = 1;

В Oracle 12C + вам не нужен подзапрос:

insert into d1 (val)
    select val
    from s1
    order by dbms_random.value
    fetch first 1 row only;

Примечание. предполагает, что вы действительно имеете в виду случайный , а не произвольный. Случайная строка означает, что любая строка в таблице имеет равные шансы быть выбранной при любом данном вызове запроса.

...