Oracle 是不是关联嵌套在任何级别的子查询?
Posted
技术标签:
【中文标题】Oracle 是不是关联嵌套在任何级别的子查询?【英文标题】:Does Oracle correlate a subquery nested at any level?Oracle 是否关联嵌套在任何级别的子查询? 【发布时间】:2016-05-19 13:20:34 【问题描述】:我看到这个论坛关于同一主题的不同问题,一个固定且经常出现的回答是:
不,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;
【问题讨论】:
Oracle 12c 支持超过一层深度的关联。所有之前的版本都只有一个级别。 【参考方案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
reference - 查询有效。
【讨论】:
【参考方案2】:如果您要将子查询连接到表(或另一个子查询),那么所有连接条件都必须在 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));
【讨论】:
我已经用替代建议更新了我的答案。出于好奇,您的标题和详细信息表中有多少行?此外,您是否希望从主表和其他详细表中返回相同的数据?因为如果数据是完全分离的,那么您可以使用 UNION ALL 并为自己保存一个 sort/distinct 操作。 很好,但实际查询有 8 个子选择表和 5 个主表,因此在不丢失 UNION 的完整性的情况下无法轻松完成连接,以作为针对主表的限制条件桌子。因此,UNION 是其他 4 个类似的 UNION 之一。如上面编辑过的帖子所示,在 MS SQL 中进行测试时,性能从 9 分钟变为 30-40 秒。它在 Oracle 中的运行时间非常相似,大约为 9 分钟。我们希望获得与 MS SQL 一样的优势。 如果您可以使用更准确地反映您的实际查询的示例查询来更新您的问题,我们或许可以提出您可以做出的改进建议。 页眉超过 4 亿行,细节超过 14 亿行。因此,为什么我也很快变得讨厌 Oracle 不允许我在明细表的 Header_ID 字段上设置聚集索引。在 MS SQL 中管理表的聚集索引是传统上使我在优化数据库时成为超级明星的“魔法”。 一个快速的谷歌揭示:dba.stackexchange.com/questions/7951/… - 也许在 Oracle 中将头表重新创建为 IOT 可能会给您带来一些额外的性能优势?这是假设 header 不是一个宽表。以上是关于Oracle 是不是关联嵌套在任何级别的子查询?的主要内容,如果未能解决你的问题,请参考以下文章