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. 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.
Consider EMP as
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
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:
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. The sqldeveloper tool to toggle between join methods gives me this
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?
CodePudding user response:
You can use a CASE
expression in the JOIN
:
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 |
CodePudding user response:
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
EMP.EmpID,
EMP.Department,
case when Emp.Department = 'Corporate' then OVERHEAD.Overhead end as CorpOverhead
from EMP,
OVERHEAD
where
OVERHEAD.EmpID( ) = EMP.EmpID
CodePudding user response:
WHERE
will eliminate all rows that don't fit the WHERE
clause
If you want to exclude values ,you ueed a 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't want to know how old your developer is as JOIN
s are literary 30 Years in sql standard
CodePudding user response:
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
CodePudding user response:
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. 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). Of course, millage may vary according to DB version. 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.