Выбор случайной строки в Oracle

Мне нужно случайным образом выбрать значения из одной таблицы, например. tableA.a_id, который является VARCHAR2, и используйте это значение для вставки в другую таблицу. Например, предположим, что необходимо вставить три столбца в 100 строк tableX (порядковый номер, случайное число от 100 до 999 и значения tableA.a_id):

insert into tableX
select
    rownum,
    dbms_random.value(100,999), 0),
    (select a_id from 
    (
      SELECT a_id 
      FROM tableA
      ORDER BY dbms_random.value
    )
    where rownum = 1)
from
   (select level from dual connect by level <= 100);

Однако вместо того, чтобы выбирать случайную строку из tableA.a_id для каждой строки, он выбирает одно и то же значение для всех строк, например:

1 129 A-ID-48
2 849 A-ID-48
3 367 A-ID-48

Однако, если я выполняю подзапрос повторно, я каждый раз получаю новое значение (по очевидной причине), например:

select a_id from 
    (
      SELECT a_id 
      FROM tableA
      ORDER BY dbms_random.value
    )
where rownum = 1;

Результат будет после каждого выполнения:

A-ID-7
A-ID-48
A-ID-74

Как мне изменить исходный запрос или придумать новый, если на то пошло, который будет вставлять случайные строки из столбца a_id tableA для каждой вставляемой строки в целевую таблицу? Желаемый результат:

1 129 A-ID-7
2 849 A-ID-48
3 367 A-ID-74

Обновление 1

Основываясь на ответе mathguy, я обновил запрос для выбора одной таблицы:

insert into tableX
select
    rownum,
    round(dbms_random.value(100,999), 0),
    a_id
from
    (
      select 
        round(dbms_random.value(1, (select count(*) from tableA)), 0) tableX_rand_num
      from tableX
    ) x
join 
    (
      select
        a_id, 
        dbms_random.value() rnd,
        rownum tableA_rownum
      from tableA
      order by rnd
    ) a
on x.tableX_rand_num = a.tableA_rownum
where rownum <= 100;

ОГРАНИЧЕНИЕ: количество вставляемых строк с использованием этого метода не будет зависеть от количества записей, доступных в родительской таблице (tableX). Другими словами, вы можете вставить столько записей, сколько всего строк доступно в tableX. например если tableX имеет 200 записей, а вы хотите вставить 1000, приведенный выше запрос позволит вам вставить только до 200 строк.


person NuCradle    schedule 27.08.2016    source источник


Ответы (1)


Сделайте внутренний запрос:

select a_id, dbms_random.value() rnd from tableA order by rnd

а затем во внешнем запросе выберите 100 строк за один раз с помощью rownum <= 100.

Вот так:

insert into tableX
select
    rownum,
    round(dbms_random.value(100,999), 0),
    a_id
from
    (
      SELECT a_id, dbms_random.value() rnd
      FROM tableA
      ORDER BY rnd
    )
where rownum <= 100;
person mathguy    schedule 27.08.2016
comment
Я не совсем понимаю вашу логику. Для какого внутреннего запроса мне нужно сделать замену? Разве мне не нужно where rownum = 1 для первого внутреннего запроса, чтобы вернуть только одну запись? - person NuCradle; 27.08.2016
comment
Было проще добавить полный запрос к ответу. См. выше. Я снова добавил round(, который вы, кажется, удалили случайно. - person mathguy; 27.08.2016
comment
Не думаю, что изменения прошли. :) - person NuCradle; 27.08.2016
comment
Примечание. Это вернет 100 различных строк (что не совсем случайно). Если вы хотите, чтобы они были действительно случайными, это тоже можно сделать, но часто люди хотят рисовать отдельные строки. - person mathguy; 27.08.2016
comment
Хорошо, но что, если есть дополнительные таблицы, например. tableY.y_id, из которого запрос должен получить случайные строки? Как несколько дочерних таблиц, первичные ключи которых должны быть вставлены в родительскую таблицу случайным образом? Кроме того, tableA в этом примере намного меньше, чем tableX, поэтому ожидаются дубликаты из tableA.a_id (то же самое с tableY.y_id). - person NuCradle; 27.08.2016
comment
Это дополнительные требования и информация, которых нет в исходном вопросе. Это не то, как вы должны просить о помощи. С учетом сказанного: вы можете выбирать строки из нескольких таблиц одинаково. Так как tableA намного меньше, чем tableX, вам нужно будет добавить row_number() в tableA, сгенерировать случайные числа от 1 до count(*) из tableA для tableX и выполнить объединение этих случайных чисел, соответствующих row_number() в дополненной таблицеA. Если вам нужна дополнительная помощь, отредактируйте свой вопрос или откройте новую тему. - person mathguy; 27.08.2016
comment
Обычно я начинаю с устранения всех сложностей и сосредотачиваюсь на основной проблеме. Однако иногда, когда вам задают вопрос, вы не знаете, как тот или иной ответ приведет вас к чему-то, что, как вы предполагали, может быть легко расширено с помощью этого решения. В любом случае, благодарю вас за помощь, и я попытаюсь найти способ использовать несколько разрозненных таблиц с одним и тем же решением. - person NuCradle; 27.08.2016