我遇到了关于 Oracle 12c 上丢失数据的问题。
我查看了代码,发现一个查询适用于 mysql、mssql、oracle 11g,但在 oracle 12c 中具有不同的行为。
我已经概括了表结构和查询并重现了这个问题。
create table thing (thing_id number, display_name varchar2(500));
create table thing_related (related_id number, thing_id number, thing_type varchar2(500));
create table type_a_status (related_id number, status varchar2(500));
create table type_b_status (related_id number, status varchar2(500));
insert into thing values (1, 'first');
insert into thing values (2, 'second');
insert into thing values (3, 'third');
insert into thing values (4, 'fourth');
insert into thing values (5, 'fifth');
insert into thing_related values (101, 1, 'TypeA');
insert into thing_related values (102, 2, 'TypeB');
insert into thing_related values (103, 3, 'TypeB');
insert into thing_related (related_id, thing_id) values (104, 4);
insert into type_a_status values (101, 'OK');
insert into type_b_status values (102, 'OK');
insert into type_b_status values (103, 'NOT OK');
运行查询:
SELECT t.thing_id AS id, t.display_name as name,
tas.status as type_a_status,
tbs.status as type_b_status
FROM thing t LEFT JOIN thing_related tr
ON t.thing_id = tr.thing_id
LEFT JOIN type_a_status tas
ON (tr.related_id IS NOT NULL
AND tr.thing_type = 'TypeA'
AND tr.related_id = tas.related_id)
LEFT JOIN type_b_status tbs
ON (tr.related_id IS NOT NULL
AND tr.thing_type = 'TypeB'
AND tr.related_id = tbs.related_id)
在 Oracle 11g 上给出(这里是一个SQL Fiddle):
ID | NAME | TYPE_A_STATUS | TYPE_B_STATUS
1 | first | OK | (null)
2 | second | (null) | OK
3 | third | (null) | NOT OK
4 | fourth | (null) | (null)
5 | fifth | (null) | (null)
然而,Oracle 12c 上的模式、数据和查询相同:
ID | NAME | TYPE_A_STATUS | TYPE_B_STATUS
1 | first | OK | (null)
2 | second | (null) | OK
3 | third | (null) | NOT OK
4 | fourth | (null) | (null)
似乎后两个外部联接无法带回任何东西,因为“thing_related”中没有可以加入的行。但是我不明白为什么在这种情况下外连接不会像在 Oracle 11g、Mysql 等中那样返回空值。
我一直在研究并发现文档 Oracle 12c 对外部连接进行了许多增强,但没有突出显示会影响这一点的更改。
有谁知道为什么这只发生在 Oracle 12c 上,我将如何最好地重写它以在 12c 中工作并保持与 11g、mysql 等的兼容性?
编辑:附加计划。
甲骨文 11g:
甲骨文 12c: