oracle中的全外连接
Posted
技术标签:
【中文标题】oracle中的全外连接【英文标题】:FULL OUTER JOIN in oracle 【发布时间】:2013-02-25 06:45:00 【问题描述】:我刚刚注意到 FULL OUTER JOIN
在 Oracle 中不起作用。
其他查询工作正常,但是当我使用完全外连接触发查询时,它需要时间并且断开连接并抛出错误。
ORA-03113:通信通道上的文件结束
RIGHT OUTER JOIN 和 LEFT OUTER JOIN 工作正常。
对于下面我使用完全外连接获取所有记录的查询,有什么替代方法?
select * from
(
select
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID in (select distinct FDP_DHARAUTI_C_ACC_ID from FMS_DHARAUTI_PARAMETER where FDP_FISCAL_YEAR='2066/67' )
/*and FTD_ACC_ID in (591)*/
group by FTM_OFFICE_ID
) T1
full outer join
(
select
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
/*and FTD_ACC_ID in (592)*/
and FTD_ACC_ID in
(select distinct FDP_DHARAUTI_L_ACC_ID from FMS_DHARAUTI_PARAMETER where FDP_FISCAL_YEAR='2066/67' )
group by FTM_OFFICE_ID
) T2
on T1.FTM_OFFICE_ID=T2.FTM_OFFICE_ID
/*
The no. of rows that T1 can have can be different that no. of rows T2 can have.
Its not necessary any OFFICE_ID must have amount under any FTD_ACC_ID.
*/
刚刚注意到,如果我在FTD_ACC_ID
的条件下删除子查询,查询就会完美运行。为什么?
【问题讨论】:
“不起作用”到底是什么意思? Oracle 很好地支持全外连接。 @FrankSchmitt:上面写着“ORA-03113: end-of-file on communication channel”,我在某处读到了 Oracle 不支持完全外连接。 @hsuk 您是否检查了用户转储区域中的任何跟踪文件?很可能有一个用户转储与幕后相关的 ORA-00600/7445。 @hsuk 尝试禁用外部连接的优化。alter session set _optimizer_cost_based_transformation=off;
或在 sql 中作为提示 /*+ opt_param('_optimizer_cost_based_transformation', 'off')
。使用复杂的 SQL 时有几个 ANSI 错误,尤其是在 10g 初始版本中。如果这不能解决问题,那么您应该联系 Oracle 支持,假设您有访问权限,因为列出的几个错误可能与此错误匹配
@hsuk 因为它是你击中的错误。并给定转储参数+您的跟进,可能的错误是BUG 4204383: ORA-7445[KKQTNLOCBK] USING QUERY WITH SUBQUERY AND FULL OUTER JOIN
(修复了 10.2.0.4,可向后移植回 10.2.0.2)。如果该错误是正确的,我提供的解决方法也应该有效。
【参考方案1】:
基于您的查询 + 后续 cmets 的解决方法是:
alter session set "_optimizer_cost_based_transformation"=off;
例如:
SQL> alter session set "_optimizer_cost_based_transformation"=off;
Session altered.
或在sql中作为提示
/*+ opt_param('_optimizer_cost_based_transformation', 'off')
例如
select /*+ opt_param('_optimizer_cost_based_transformation', 'off') */ * from
(
select FTM_OFFICE_ID,
你可能遇到了错误:
BUG 4204383: ORA-7445[KKQTNLOCBK] USING QUERY WITH SUBQUERY AND FULL OUTER JOIN
仅在 10.2.0.2 及更高版本中可用的补丁(在 10.2.0.4 中完全修复)。
【讨论】:
我得到 ORA-00972: identifier is too long 当我尝试触发alter session set_optimizer_cost_based_transformation=off;
时,我无法理解第二个,sql 作为提示 .
@hsuk 你需要把它放在引号里。即不是alter session set_optimizer_cost_based_transformation
,而是alter session set "_optimizer_cost_based_transformation"
即set 是一个单独的词,名称用引号引起来。
@hsuk 还可以查看如何将提示版本放入 SQL 中的编辑。【参考方案2】:
FULL OUTER JOIN
在 Oracle 中得到很好的支持。
您遇到的错误听起来像是 Oracle 错误,或者可能是某种形式的损坏。每当发生 ORA-03113 时,您应该会发现在 alert.log
中记录的错误。
如果您收到此错误,通常是因为该会话的后台 oracle 系统进程已终止(这几乎总是由于 Oracle 内部错误)。
这对您友好的本地 DBA 来说是个问题。
【讨论】:
【参考方案3】:如果确实(无论出于何种原因)完全外部联接对您不起作用,请使用
-- all rows present in both t1 and t2
select * from t1 inner join t2
union all
-- all rows present in t1 but not in t2
select * from t1 left outer join t2 where t2.pk is null
union all
-- all rows present in t2 but not in t1
select * from t1 right outer join t2 where t1.pk is null
而不是
select * from t1 full outer join t2
这将返回相同的结果。
【讨论】:
非常感谢。但我仍然试图弄清楚为什么完全外部连接不起作用。临时表空间似乎有问题。【参考方案4】:你可以试试这个查询:
SELECT
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) AS TOTAL
FROM FMS_TRANS_DTL
INNER JOIN FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
INNER JOIN FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
WHERE FFVC_ACCOUNT_TYPE = 3 AND FTM_FISCAL_YEAR='2066/67'
AND FTD_ACC_ID IN (
SELECT DISTINCT FDP_DHARAUTI_C_ACC_ID FROM FMS_DHARAUTI_PARAMETER WHERE FDP_FISCAL_YEAR='2066/67'
UNION
SELECT DISTINCT FDP_DHARAUTI_L_ACC_ID FROM FMS_DHARAUTI_PARAMETER WHERE FDP_FISCAL_YEAR='2066/67'
)
GROUP BY FTM_OFFICE_ID
【讨论】:
:感谢您的回复,但这不是我需要的。此查询根据单列上的 OFFICE_ID 给出金额的总和。但我想要根据 OFFICE_ID 在不同列上的金额总和。总金额应根据账户头、FDP_DHARAUTI_C_ACC_ID和FDP_DHARAUTI_L_ACC_ID按照不同的OFFICE_ID进行区分。无论如何,我在问是否有 FULL OUTER JOIN 的替代方案。 :)【参考方案5】:看起来唯一不同的是 FTD_ACC_ID 值为 105 和 110 的单独总计。一种方法是使用 CASE 语句分别总计。
select
FTM_OFFICE_ID,
NVL(SUM(CASE FTD_ACC_ID WHEN 105 THEN FTD_NRS_AMOUNT ELSE 0 END),0) as TOTAL_105,
NVL(SUM(CASE FTD_ACC_ID WHEN 110 THEN FTD_NRS_AMOUNT ELSE 0 END),0) as TOTAL_110,
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID in (105,110)
group by FTM_OFFICE_ID
【讨论】:
哦,好吧。对于“是否有替代完整外部联接”的问题,答案几乎总是肯定的,但这取决于您尝试通过整体查询实现/检索的内容。没有通用的用 X 代替它的答案。【参考方案6】:像这样在查询中使用UNION
而不是FULL OUTER JOIN
select * from
(
select
FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID = 105
group by FTM_OFFICE_ID ) T1 union (select FTM_OFFICE_ID,
NVL(SUM(FTD_NRS_AMOUNT),0) as TOTAL
from FMS_TRANS_DTL
inner join FMS_TRANS_MST ON FMS_TRANS_MST.FTM_TRANS_MST_ID = FMS_TRANS_DTL.FTD_TRANS_MST_ID
inner join FMS_FC_VOUCHER_CONFIG ON FMS_FC_VOUCHER_CONFIG.FFVC_VOUCHER_ID = FMS_TRANS_MST.FTM_VOUCHER_ID
where FFVC_ACCOUNT_TYPE = 3 and FTM_FISCAL_YEAR='2066/67'
and FTD_ACC_ID = 110
group by FTM_OFFICE_ID )T2
【讨论】:
这行不通 - 你不能在 UNION 中有一个 ON 子句,即使它被允许,它也不会返回 OP 所需的结果(你的查询将返回 2 行ftd_acc_id 105 和 110 的 ftm_office_id)以上是关于oracle中的全外连接的主要内容,如果未能解决你的问题,请参考以下文章