SQL 相关子查询

SQL Correlated subquery

我正在尝试执行此查询,但收到 ORA-00904:"QM"."MDL_MDL_ID": 无效标识符。更让我困惑的是主查询有两个子查询,它们只在 where 子句上有所不同。但是,第一个查询 运行 没问题,但第二个查询出错。下面是查询。

select (
        select make_description
        from make_colours@dblink1
        where makc_id = (
                select makc_makc_id
                from model_colours@dblink1
                where to_char(mdc_id) = md.allocate_vehicle_colour_id
                )
        ) as colour,
    (
        select make_description
        from make_colours@dblink1
        where makc_id = (
                select makc_makc_id
                from model_colours@dblink1
                where mdl_mdl_id = qm.mdl_mdl_id
                )
        ) as vehicle_colour
from schema1.web_order wo,
    schema1.tot_order tot,
    suppliers@dblink1 sp,
    external_accounts@dblink1 ea,
    schema1.location_contact_detail lcd,
    quotation_models@dblink1 qm,
    schema1.manage_delivery md
where wo.reference_id = tot.reference_id
    and sp.ea_c_id = ea.c_id
    and sp.ea_account_type = ea.account_type
    and sp.ea_account_code = ea.account_code
    and lcd.delivery_det_id = tot.delivery_detail_id
    and sp.sup_id = tot.dealer_id
    and wo.qmd_id = qm.qmd_id
    and wo.reference_id = md.web_reference_id(+)
    and supplier_category = 'dealer'
    and wo.order_type = 'tot'
    and trunc(wo.confirmdeliverydate - 3) = trunc(sysdate)

Oracle 通常不会识别 table 别名(或其他任何)嵌套子查询中超过一级的别名; from the documentation:

Oracle performs a correlated subquery when a nested subquery references a column from a table referred to a parent statement one level above the subquery. [...] A correlated subquery conceptually is evaluated once for each row processed by the parent statement.

注意 'one level' 部分。因此,在嵌套子查询中,您的 qm 别名未被识别,因为它与 qm 别名的定义相距两个级别。 (如果你没有给它起别名,原来的 table 名字也会发生同样的事情——它不是专门与别名有关的)。

当您将查询修改为只有 select qm.mdl_mdl_id as Vehicle_colour - 或者它的有效版本,可能是 (select qm.mdl_mdl_id from dual) as Vehicle_colour - 您删除了嵌套,qm 现在只有一层低于查询主体中的定义,所以它被识别了。

您在第一个嵌套子查询中对 md 的引用可能也不会被识别,但解析器倾向于向后工作,因此它首先看到 qm 问题;尽管查询重写可能会使它有效:

However, the optimizer may choose to rewrite the query as a join or use some other technique to formulate a query that is semantically equivalent.

您也可以添加提示来鼓励这样做,但最好不要依赖它。

但是你不需要嵌套子查询,你可以在每个顶级子查询中加入:

select (
        select mc2.make_description
        from model_colours@dblink1 mc1,
            make_colours@dblink1 mc2  
        where mc2.makc_id = mc1.makc_makc_id
        and to_char(mc1.mdc_id) = md.allocate_vehicle_colour_id
    ) as colour,
    (
        select mc2.make_description
        from model_colours@dblink1 mc1,
            make_colours@dblink1 mc2
        where mc2.makc_id = mc1.makc_makc_id
        and mc1.mdl_mdl_id = qm.mdl_mdl_id
    ) as vehicle_colour
from schema1.web_order wo,
...

我坚持使用 old-style 连接语法来匹配主查询,但您真的应该考虑使用现代 ANSI 连接语法重写整个内容。 (我还删除了@Serg 提到的流氓逗号,但您可能只是在发布问题时遗漏了真实 select 列表中的其他列。)

您可以通过在主查询中加入品牌和型号颜色 table 来完全避免子查询,两次处理单独的过滤条件,或者一次在列表达式中加入一些逻辑.虽然一次一步...