Home > Net >  Old Oracle (non-ansi) join syntax for more complex join conditions (Oracle 12c)
Old Oracle (non-ansi) join syntax for more complex join conditions (Oracle 12c)

Time:09-26

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

fiddle

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

db<>fiddle

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 JOINs 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.

  • Related