简体   繁体   English

用于更复杂连接条件的旧 Oracle(非 ansi)连接语法(Oracle 12c)

[英]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 1 Retail零售
2 2 Retail零售
3 3 Corporate公司的
4 4 Corporate公司的
5 5 Corporate公司的

and OVERHEAD as和开销为

EmpID企业标识 Overhead高架
1 1 $10 10 美元
2 2 $20 20 美元
3 3 $100 100 美元
4 4 $120 120 美元
5 5 $220 220 美元

I am trying to denormalize for olap, so I want to do something like this我正在尝试对 olap 进行非规范化,所以我想做这样的事情

EmpID企业标识 Department部门 CorpOverhead公司开销
1 1 Retail零售 null null
2 2 Retail零售 null null
3 3 Corporate公司的 $100 100 美元
4 4 Corporate公司的 $120 120 美元
5 5 Corporate公司的 $220 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 3 Corporate公司的 $100 100 美元
4 4 Corporate公司的 $120 120 美元
5 5 Corporate公司的 $220 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 EMPID DEPARTMENT CORPOVERHEAD公司开销
3 3 Corporate公司的 100 100
4 4 Corporate公司的 120 120
5 5 Corporate公司的 220 220
1 1 Retail零售 null null
2 2 Retail零售 null null

fiddle小提琴

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

db<>fiddle db<>小提琴

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM