代码之家  ›  专栏  ›  技术社区  ›  Nate Cook

在某些版本的Oracle中,是否存在相关子查询的嵌套限制?

  •  7
  • Nate Cook  · 技术社区  · 15 年前

    以下代码将帮助您理解我的问题:

    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 
    

    对于嵌套的相关子查询?有某种筑巢限制吗?需要为结果集中的每一行运行此子查询,因为结果将根据内容\u id而更改,每一行的内容\u 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中的单个select查询中完成此操作,而不使用循环表和/或临时表?

    3 回复  |  直到 6 年前
        1
  •  8
  •   Jon Heller TenG    6 年前

    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
    
        2
  •  3
  •   Community Jaime Torres    7 年前

    @Quassnoi Oracle9就是这样。从Oracle 10…

    Oracle Database SQL Reference 10g Release 1 (10.1) 当嵌套的子查询引用父语句引用的表中的列时,Oracle将执行相关的子查询。 任意数量的级别 子查询上方

    Oracle9i SQL Reference Release 2 (9.2) 当子查询引用中引用的表中的列时,Oracle将执行相关的子查询。 起源 语句。

    中的子查询 哪里 select语句的子句也称为嵌套子查询。在嵌套子查询中最多可以嵌套255个级别的子查询。

    如果你有类似的东西 select*from(select*from(select*from(….)))
    只是 select*from tablename alias,其中colname=(select*from sometable,其中somecol=(select*from sometable x,其中x.id=alias.col))。

    退房 http://forums.oracle.com/forums/thread.jspa?threadID=378604

        3
  •  1
  •   Nate Cook    15 年前

    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);
    

    谢谢!