Oracle是否关联嵌套在任何级别的子查询?

时间:2016-05-19 13:20:34

标签: sql oracle correlated-subquery

我在这个论坛上看到关于同一主题的不同问题,一个罐装且频繁出现的回复是:

  

不,Oracle没有关联嵌套多个级别的子查询(MySQL也没有)。

我将从中得出结论,Oracle确实将一个子查询关联到一个层次。但是,我有以下查询,它返回此错误消息:

  

ORA-00904:“CD”。“FIELD6”:无效标识符

此查询非常重要,并且只是涉及UNION语句的实际查询的简化版本。在调试返回错误消息的原因时,我将其缩减为最简单的版本(如下所示)。我意识到这个最简单的版本可能有替代的JOIN方法,但这种替代方法不适用于实际查询。如果以下可以工作,那么看起来我们更复杂的查询也可以工作。如果以下内容无效,那么我在Oracle的文档和上面的“预制”答案中读取的内容是错误的?

SELECT a.*
FROM
    main_detail cd INNER JOIN
    (
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM other_detail x2
    WHERE x2.Field1 = cd.Field1 AND x2.Field6 = cd.Field6
    ) a ON
    a.Field1 = cd.Field1
    AND a.Field4 = cd.Field4
    AND a.Field6 = cd.Field6

以下更类似于我们的实际需要。 UNION需要保持返回的UNION-ed集合上的JOIN,因为它被用作INNER JOIN来限制返回记录集:

SELECT h.*, a.*
FROM
    header h,
    (
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM main_detail x1
    WHERE x1.Field1 = h.Field1 AND x1.Field6 = h.Field6
    UNION
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM other_detail x2
    WHERE x2.Field1 = h.Field1 AND x2.Field6 = h.Field6
    ) a
    WHERE
        a.Field1 = h.Field1 AND
        a.Field6 = h.Field6

当将上述内容与不包括相关子查询参数进行比较,并在MS SQL中测试运行时,它将性能从9分钟提高到30-40秒,这是一个非常可观的改进。我希望在Oracle中获得同样的收益。

以下是我对实际代码的尽可能接近,而不会影响客户端的机密性:

SELECT DISTINCT 
    c.Field1,
    c.Field2,
    D.Field3,
    b.Field4,
    b.Field5,
    c.Field6,
    c.Field7 || '-' || cds1.Field8 AS status,
    b.paid,
    cds.Field8,
    p.Field9,
    p.Field10,
    c.Field11,
    c.Field12 AS provider_name
FROM
    header c,
    (
    SELECT
        a.*,
        cd.paid,
        cd.Field15,
        cd.BigList,
        cd.allowed,
        cd.copayment,
        cd.coinsurance
    FROM
        header_detail cd,
        (
        SELECT
            Field1,
            Field4,
            '' AS revenue_code,
            Field20,
            Field5,
            Field14,
            location_code,
            ServiceList
        FROM header_other_detail x1
        WHERE x1.Field1 = cd.Field1 AND x1.Field14 = cd.Field14
        UNION
        SELECT
            Field1,
            Field4,
            revenue_code,
            Field20,
            Field5,
            Field14,
            '' AS location_code,
            ServiceList
        FROM inst_claim_detail x2
        WHERE x2.Field1 = cd.Field1 AND x2.Field14 = cd.Field14
        ) a
    WHERE
        a.Field1 = cd.Field1
        AND cd.Field1 = c.Field1
        AND a.Field20 = cd.Field20
        AND a.Field14 = cd.Field14
        AND cd.Field14 = c.Field14a
    ) b,
    (
    SELECT
        Field1,
        Field14,
        Trim(
            Trailing ',' FROM
            ch.icd9_1  || ',' ||
            ch.icd9_2  || ',' ||
            ch.icd9_3  || ',' ||
            ch.icd9_4  || ',' ||
            ch.icd9_5  || ',' ||
            ch.icd9_6  || ',' ||
            ch.icd9_7  || ',' ||
            ch.icd9_8  || ',' ||
            ch.icd9_9  || ',' ||
            ch.icd9_10 || ',' ||
            ch.icd9_11 || ',' ||
            ch.icd9_12
            )
        AS Field3
    FROM prof_claim ch
    WHERE ch.Field1 = c.Field1 AND ch.Field14 = c.Field14a
    UNION
    SELECT
        Field1,
        Field14,
        Field3
    FROM inst_claim x3
    WHERE x3.Field1 = c.Field1 AND x3.Field14 = c.Field14a
    ) d,
    (
    SELECT
        Field1,
        Field14,
        Field9,
        Field10,
        Field18,
        refund_amount,
        Field15
    FROM payment_detail
    ) p,
    (SELECT * FROM Codes WHERE code_type='19') cds,
    (SELECT * FROM Codes WHERE code_type='28') cds1
WHERE
    c.Field17 = 'T00000370'
    AND c.Field1 = b.Field1 AND c.Field14a = b.Field14
    AND c.Field1 = d.Field1 AND c.Field14a = d.Field14
    AND b.Field14 = p.Field14(+) AND b.Field1 = p.Field1(+) AND b.Field15 = p.Field15(+)
    AND b.BigList = cds.Field16(+) AND b.Field14 = cds.Field14(+)
    AND c.Field7 = cds1.Field16(+) AND c.Field14a = cds1.Field14(+)
ORDER BY Field1;

2 个答案:

答案 0 :(得分:1)

在子查询中

SELECT
    Field1,
    Field2,
    Field3,
    Field4,
    Field5,
    Field6,
    Field7
FROM other_detail x2
WHERE x2.Field1 = cd.Field1 AND x2.Field6 = cd.Field6

检查where条件。如果完全删除或至少删除了cd引用 - 查询可以正常工作。

答案 1 :(得分:0)

如果要将子查询加入表(或其他子查询),则所有连接条件必须位于ON子句中,如果您使用的是ANSI样式连接。

您的查询失败的原因是a子查询的范围不会扩展到自身之外。它完全独立于main_detail表的范围,因为您尝试连接表,而不是关联它们。正如Marmite Bomber的回答所示,子查询需要能够独立运行,而你的尝试版本却没有。

您需要做的是将相关过滤器移动到ON子句,如下所示:

SELECT a.*
FROM
    main_detail cd INNER JOIN
    (
    SELECT
        Field1,
        Field2,
        Field3,
        Field4,
        Field5,
        Field6,
        Field7
    FROM other_detail x2) a ON
    a.Field1 = cd.Field1
    AND a.Field4 = cd.Field4
    AND a.Field6 = cd.Field6
    and a.Field1 = cd.Field1 AND a.Field6 = cd.Field6

当然,它与:

相同
SELECT a.*
FROM
    main_detail cd INNER JOIN
    other_detail a ON
      a.Field1 = cd.Field1
      AND a.Field4 = cd.Field4
      AND a.Field6 = cd.Field6

关于您使用UNION的查询,这应该有助于您比原始查询带来一些性能优势:

SELECT *
FROM   (SELECT h1.*,
               x1.field1,
               x1.field2,
               x1.field3,
               x1.field4,
               x1.field5,
               x1.field6,
               x1.field7
        FROM   main_detail x1
               inner join header h1 on (x1.Field1 = h1.Field1 AND x1.Field6 = h1.Field6)
        UNION
        SELECT h2.*
               field1,
               field2,
               field3,
               field4,
               field5,
               field6,
               field7
        FROM   other_detail x2
               inner join header h2 on (x2.Field1 = h2.Field1 AND x2.Field6 = h2.Field6));