Как заставить oracle выполнять подзапрос для каждой строки?

#sql #oracle

#sql #Oracle

Вопрос:

У меня есть две таблицы, и я хочу выбрать случайное значение из второй таблицы для каждой записи в первой. Проблема в том, что кажется, что это значение всегда одинаково для каждой строки, что означает, что оно выполняется только один раз для всех строк. Как я мог этого добиться?

 create table first_table(name varchar2(100));
insert into first_tablevalues('John');
insert into first_tablevalues('Jessie');
insert into first_tablevalues('Jack');

select * from second_table;
create table second_table(id number);
insert into second_table(id) values(1);
insert into second_table(id) values(2);
insert into second_table(id) values(3);
insert into second_table(id) values(4);
insert into second_table(id) values(5);
insert into second_table(id) values(6);
  

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

 SELECT NAME,
       (SELECT id
          FROM (SELECT id
                  FROM second_table
                 ORDER BY dbms_random.value)
         WHERE rownum = 1)
  FROM first_table;
  

Ответ №1:

Предложение корреляции устраняет проблему:

 SELECT NAME,
       (SELECT id
        FROM (SELECT id
              FROM second_table st
              ORDER BY dbms_random.value
             )
        WHERE rownum = 1 AND ft.name IS NOT NULL
       )
FROM first_table ft;
  

Вот rextester.

Комментарии:

1. Извините, но это не только не сработало, но и продублировало мой результирующий набор три раза (по одному разу для каждого имени, я думаю).

2. Теперь это именно то, что я хотел! Большое вам спасибо!

Ответ №2:

Это некрасиво, но работает.

 SQL> WITH ri
  2       AS (SELECT s.id,
  3                  ROW_NUMBER () OVER (ORDER BY DBMS_RANDOM.VALUE) rn,
  4                  COUNT (*) OVER (ORDER BY NULL) cnt
  5             FROM second_table s),
  6       rn
  7       AS (SELECT f.name,
  8                  ROW_NUMBER () OVER (ORDER BY DBMS_RANDOM.VALUE (1, ri.cnt))
  9                     rn
 10             FROM first_table f JOIN ri ON 1 = 1)
 11    SELECT rn.name, MAX (ri.id) id
 12      FROM rn JOIN ri ON rn.rn = ri.rn
 13  GROUP BY rn.name;

NAME               ID
---------- ----------
Jack                3
John                2
Jessie              6

SQL> /

NAME               ID
---------- ----------
John                5
Jack                6
Jessie              4

SQL> /

NAME               ID
---------- ----------
Jack                6
John                2
Jessie              4

SQL> /

NAME               ID
---------- ----------
Jack                5
John                6
Jessie              3

SQL> /

NAME               ID
---------- ----------
John                6
Jack                3
Jessie              1

SQL>
  

Комментарии:

1. Самое главное, что это работает! Спасибо, я ценю это.

2. Пожалуйста. Хотя запрос Гордона, похоже, намного лучше.