[英]Old Oracle (non-ansi) join syntax for more complex join conditions (Oracle 12c)
I am creating a WITH ROWID, on-commit fast refresh materialized view and as I understand it, Oracle requires the query that defines the mview to use non-ansi (old oracle) style joins.我正在创建一个 WITH ROWID、提交时快速刷新物化视图,据我了解,Oracle 需要定义 mview 的查询以使用非 ansi(旧 oracle)样式连接。 I have a join that I dont know how to convert to old oracle join, and that the inbuilt Oracle conversion tool doesn't handle correctly.
我有一个连接,我不知道如何转换为旧的 oracle 连接,并且内置的 Oracle 转换工具无法正确处理。
Consider EMP as将 EMP 视为
EmpID![]() |
Department![]() |
---|---|
1 ![]() |
Retail![]() |
2 ![]() |
Retail![]() |
3 ![]() |
Corporate![]() |
4 ![]() |
Corporate![]() |
5 ![]() |
Corporate![]() |
and OVERHEAD as和开销为
EmpID![]() |
Overhead![]() |
---|---|
1 ![]() |
$10 ![]() |
2 ![]() |
$20 ![]() |
3 ![]() |
$100 ![]() |
4 ![]() |
$120 ![]() |
5 ![]() |
$220 ![]() |
I am trying to denormalize for olap, so I want to do something like this我正在尝试对 olap 进行非规范化,所以我想做这样的事情
EmpID![]() |
Department![]() |
CorpOverhead![]() |
---|---|---|
1 ![]() |
Retail![]() |
null ![]() |
2 ![]() |
Retail![]() |
null ![]() |
3 ![]() |
Corporate![]() |
$100 ![]() |
4 ![]() |
Corporate![]() |
$120 ![]() |
5 ![]() |
Corporate![]() |
$220 ![]() |
In ANSI I know how to do this, and get the result I want:在 ANSI 中,我知道如何做到这一点,并得到我想要的结果:
select
EMP.EmpID,
EMP.Department,
OVERHEAD.Overhead as CorpOverhead
from EMP
left join OVERHEAD on
OVERHEAD.EmpID = EMP.EmpID
and EMP.Department = 'Corporate'
In old Oracle, I am stumped.在旧的 Oracle 中,我很难过。 The sqldeveloper tool to toggle between join methods gives me this
在连接方法之间切换的 sqldeveloper 工具给了我这个
select
EMP.EmpID,
EMP.Department,
OVERHEAD.Overhead as CorpOverhead
from EMP,
OVERHEAD
where
OVERHEAD.EmpID(+) = EMP.EmpID
and EMP.Department = 'Corporate'
which results in这导致
EmpID![]() |
Department![]() |
CorpOverhead![]() |
---|---|---|
3 ![]() |
Corporate![]() |
$100 ![]() |
4 ![]() |
Corporate![]() |
$120 ![]() |
5 ![]() |
Corporate![]() |
$220 ![]() |
which is not what I want.这不是我想要的。
How can I write an old oracle join to accomplish the same as the ANSI join?如何编写旧的 oracle 连接来完成与 ANSI 连接相同的操作?
You can use a CASE
expression in the JOIN
:您可以在
JOIN
中使用CASE
表达式:
select e.EmpID,
e.Department,
o.Overhead as CorpOverhead
from EMP e,
OVERHEAD o
where CASE e.department WHEN 'Corporate' THEN e.EmpID END = o.EmpID (+)
Which, for your the sample data, outputs:其中,对于您的样本数据,输出:
EMPID ![]() |
DEPARTMENT![]() |
CORPOVERHEAD![]() |
---|---|---|
3 ![]() |
Corporate![]() |
100 ![]() |
4 ![]() |
Corporate![]() |
120 ![]() |
5 ![]() |
Corporate![]() |
220 ![]() |
1 ![]() |
Retail![]() |
null ![]() |
2 ![]() |
Retail![]() |
null ![]() |
WHERE
will eliminate all rows that don't fit the WHERE
clause WHERE
将消除所有不适合WHERE
子句的行
If you want to exclude values,you ueed a CASE WHEN
如果要排除值,请使用
CASE WHEN
select
EMP.EmpID,
EMP.Department,
CASE WHEN EMP.Department = 'Corporate' THEN
OVERHEAD.Overhead ELSE NULL END as CorpOverhead
from EMP,
OVERHEAD
where
OVERHEAD.EmpID(+) = EMP.EmpID
I really don'z want to know how old your developer is as JOIN
s are literary 30 Years in sql standard我真的不想知道你的开发人员多大了,因为
JOIN
是文学 30 年在 sql 标准中
I think that if you wanted to do it just with joins then you'd need to use a subquery:我认为,如果您只想使用联接来执行此操作,则需要使用子查询:
select
EMP.EmpID,
EMP.Department,
OVERHEAD.Overhead as CorpOverhead
from EMP,
(
select
OVERHEAD.EmpID,
OVERHEAD.Overhead
from EMP,
OVERHEAD
where
OVERHEAD.EmpID = EMP.EmpID
and EMP.Department = 'Corporate'
) OVERHEAD
where
OVERHEAD.EmpID(+) = EMP.EmpID
It would be simpler, and perhaps more logical, to move that condition to a case expression in the select list:将该条件移至 select 列表中的 case 表达式会更简单,也可能更合乎逻辑:
select
EMP.EmpID,
EMP.Department,
case when Emp.Department = 'Corporate' then OVERHEAD.Overhead end as CorpOverhead
from EMP,
OVERHEAD
where
OVERHEAD.EmpID(+) = EMP.EmpID
I would suggest also laterals:我还建议横向:
select e.EmpID,
e.Department,
v.CorpOverhead
from EMP e,
lateral(
select o.Overhead as CorpOverhead
from OVERHEAD o
where e.department='Corporate'
and e.EmpID = o.EmpID
)(+) v;
DBFiddle: https://dbfiddle.uk/6IPbC4eE DBFiddle: https://dbfiddle.uk/6IPbC4eE
To avoid that kind of problems with queries not accepted by MV FAST REFRESH - even I never got the ANSI-join related one but some others (WITH clauses and other funny ones..) - I now always create a standard VIEW with all the required columns for the FAST REFRESH and then create the MV as "select * from mv_basis_view", and later I have an other VIEW on the MV without the unnecessary columns for the "business" use.为了避免 MV FAST REFRESH 不接受的查询出现这种问题——即使我从来没有得到与 ANSI-join 相关的问题,但有一些其他问题(WITH 子句和其他有趣的......)——我现在总是创建一个包含所有必需的标准视图FAST REFRESH 的列,然后将 MV 创建为“从 mv_basis_view 中选择 *”,然后我在 MV 上有另一个 VIEW,没有用于“业务”使用的不必要的列。 This pattern often solves the problem, more extreme problematics have to be solved by "cutting" the original MV into 2 (or more) MVs, and doing the desired job on them in standard VIEWs (with the correct indexes on the intermediary MVs it remains quite efficient).
这种模式通常可以解决问题,更极端的问题必须通过将原始 MV“切割”为 2 个(或更多)MV,并在标准 VIEW 中对它们进行所需的工作(在中间 MV 上保留正确的索引)来解决相当有效)。 Of course, millage may vary according to DB version.
当然,millage 可能会根据 DB 版本而有所不同。 Note also that you can often get the old-style JOIN query from the ANSI-style one by using DBMS_UTILITY.EXPAND_SQL_TEXT: it may save you some headache.
另请注意,您通常可以通过使用 DBMS_UTILITY.EXPAND_SQL_TEXT 从 ANSI 样式的查询中获取旧样式的 JOIN 查询:它可能会为您省去一些麻烦。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.