Есть ли предел вложенности для коррелированных подзапросов в некоторых версиях Oracle? - PullRequest
7 голосов
/ 05 августа 2009

Вот код, который поможет вам понять мой вопрос:

create table con ( content_id number);
create table mat ( material_id number, content_id number, resolution number, file_location varchar2(50));
create table con_groups (content_group_id number, content_id number);

insert into con values (99);
insert into mat values (1, 99, 7, 'C:\foo.jpg');
insert into mat values (2, 99, 2, '\\server\xyz.mov');
insert into mat values (3, 99, 5, '\\server2\xyz.wav');
insert into con values (100);
insert into mat values (4, 100, 5, 'C:\bar.png');
insert into mat values (5, 100, 3, '\\server\xyz.mov');
insert into mat values (6, 100, 7, '\\server2\xyz.wav');

insert into con_groups values (10, 99);
insert into con_groups values (10, 100);

commit;

SELECT m.material_id,
       (SELECT file_location 
          FROM (SELECT file_location
                  FROM mat
                 WHERE mat.content_id = m.content_id
              ORDER BY resolution DESC) special_mats_for_this_content            
         WHERE rownum = 1) special_mat_file_location                                     
  FROM mat m
 WHERE m.material_id IN (select material_id 
                           from mat
                     inner join con on con.content_id = mat.content_id
                     inner join con_groups on con_groups.content_id = con.content_id
                          where con_groups.content_group_id = 10);

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

Мой вопрос: почему я получаю ошибку

"M"."CONTENT_ID": invalid identifier 

для вложенного коррелированного подзапроса? Есть ли какой-то предел вложенности? Этот подзапрос необходимо выполнить для каждой строки в наборе результатов, поскольку результаты будут меняться в зависимости от content_id, который может отличаться для каждой строки. Как я могу сделать это с Oracle?

Не то чтобы я пытался начать обсуждение SQL Server против Oracle, но я пришел из опыта работы с SQL Server и хотел бы отметить, что следующий эквивалентный запрос работает на SQL Server нормально:

create table con ( content_id int);
create table mat ( material_id int, content_id int, resolution int, file_location varchar(50));
create table con_groups (content_group_id int, content_id int);

insert into con values (99);
insert into mat values (1, 99, 7, 'C:\foo.jpg');
insert into mat values (2, 99, 2, '\\server\xyz.mov');
insert into mat values (3, 99, 5, '\\server2\xyz.wav');
insert into con values (100);
insert into mat values (4, 100, 5, 'C:\bar.png');
insert into mat values (5, 100, 3, '\\server\xyz.mov');
insert into mat values (6, 100, 7, '\\server2\xyz.wav');

insert into con_groups values (10, 99);
insert into con_groups values (10, 100);

SELECT m.material_id,
       (SELECT file_location 
          FROM (SELECT TOP 1 file_location
                  FROM mat
                 WHERE mat.content_id = m.content_id
              ORDER BY resolution DESC) special_mats_for_this_content            
               ) special_mat_file_location                                     
  FROM mat m
 WHERE m.material_id IN (select material_id 
                           from mat
                     inner join con on con.content_id = mat.content_id
                     inner join con_groups on con_groups.content_id = con.content_id
                          where con_groups.content_group_id = 10);

Не могли бы вы помочь мне понять, почему я могу делать это в SQL Server, а не в Oracle 9i? Если существует предел вложенности, как я могу выполнить это в одном запросе выбора в Oracle, не прибегая к циклическим и / или временным таблицам?

Ответы [ 3 ]

8 голосов
/ 05 августа 2009

Последние версии Oracle не имеют ограничения, но большинство старых версий Oracle имеют предел вложенности 1 уровень глубины.

Работает на всех версиях:

SELECT  (
        SELECT  *
        FROM    dual dn
        WHERE   dn.dummy = do.dummy
        )
FROM    dual do

Этот запрос работает в 12c и 18c, но не работает в 10g и 11g. (Однако существует хотя бы одна версия 10g, которая разрешает этот запрос. И есть патч для включения этого поведения в 11g.)

SELECT  (
        SELECT  *
        FROM    (
                SELECT  *
                FROM    dual dn
                WHERE   dn.dummy = do.dummy
                )
        WHERE   rownum = 1
        )
FROM    dual do

При необходимости вы можете обойти это ограничение с помощью оконных функций (которые вы также можете использовать в SQL Server:)

SELECT  *
FROM    (
        SELECT  m.material_id, ROW_NUMBER() OVER (PARTITION BY content_id ORDER BY resolution DESC) AS rn
        FROM    mat m
        WHERE   m.material_id IN
                (
                SELECT  con.content_id
                FROM    con_groups
                JOIN    con
                ON      con.content_id = con_groups.content_id
                WHERE   con_groups.content_group_id = 10
                )
        )
WHERE   rn = 1
3 голосов
/ 09 июня 2011

@ Quassnoi Так было в случае с оракулом 9. Из Oracle 10 ...

С Справочник по базе данных Oracle, версия 10g, выпуск 1 (10.1) Oracle выполняет коррелированный подзапрос, когда вложенный подзапрос ссылается на столбец из таблицы, ссылающейся на родительский оператор на любое количество уровней над подзапросом

Из Справочник по SQL9i для Oracle9i, выпуск 2 (9.2) Oracle выполняет коррелированный подзапрос, когда подзапрос ссылается на столбец из таблицы, указанной в операторе parent .

Подзапрос в предложении WHERE инструкции SELECT также называется вложенным подзапросом. Вы можете вкладывать до 255 уровней подзапросов во вложенный подзапрос.

Я не думаю, что это работает, если у вас есть что-то вроде select * from (select * from (select * from (....))))
Просто выберите * из псевдонима TableName, где colName = (выберите * из SomeTable, где someCol = (выберите * из SomeTable, где x.id = alias.col))

Выезд http://forums.oracle.com/forums/thread.jspa?threadID=378604

1 голос
/ 05 августа 2009

Quassnoi ответил на мой вопрос о вложенности и сделал отличный звонок, предложив аналитические функции окна. Вот точный запрос, который мне нужен:

SELECT m.material_id, m.content_id,
              (SELECT max(file_location) keep (dense_rank first order by resolution desc)
                 FROM mat
                WHERE mat.content_id = m.content_id) special_mat_file_location
      FROM mat m
     WHERE m.material_id IN (select material_id
                               from mat
                         inner join con on con.content_id = mat.content_id
                         inner join con_groups on con_groups.content_id = con.content_id
                              where con_groups.content_group_id = 10);

Спасибо! * * 1004

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...