最近我修复了一些错误:在联接条件中有rownum。
像这样:left join t1 on t1.id=t2.id and rownum<2。因此,它应该只返回一行,而不管“left join”。
当我进一步研究时,我意识到我不理解Oracle如何在“left join”条件中评估rownum。
让我们创建两个示例表:主表和详细表。
create table MASTER
(
ID NUMBER not null,
NAME VARCHAR2(100)
)
;
alter table MASTER
add constraint PK_MASTER primary key (ID);
prompt Creating DETAIL...
create table DETAIL
(
ID NUMBER not null,
REF_MASTER_ID NUMBER,
NAME VARCHAR2(100)
)
;
alter table DETAIL
add constraint PK_DETAIL primary key (ID);
alter table DETAIL
add constraint FK_DETAIL_MASTER foreign key (REF_MASTER_ID)
references MASTER (ID);
prompt Disabling foreign key constraints for DETAIL...
alter table DETAIL disable constraint FK_DETAIL_MASTER;
prompt Loading MASTER...
insert into MASTER (ID, NAME)
values (1, 'First');
insert into MASTER (ID, NAME)
values (2, 'Second');
commit;
prompt 2 records loaded
prompt Loading DETAIL...
insert into DETAIL (ID, REF_MASTER_ID, NAME)
values (1, 1, 'REF_FIRST1');
insert into DETAIL (ID, REF_MASTER_ID, NAME)
values (2, 1, 'REF_FIRST2');
insert into DETAIL (ID, REF_MASTER_ID, NAME)
values (3, 1, 'REF_FIRST3');
commit;
prompt 3 records loaded
prompt Enabling foreign key constraints for DETAIL...
alter table DETAIL enable constraint FK_DETAIL_MASTER;
set feedback on
set define on
prompt Done.
然后我们有这个查询:
select * from master t
left join detail d on d.ref_master_id=t.id
结果集是可预测的:我们有来自主表的所有行和3行来自细节表,这些行满足条件d.ref_master_id=t.id。
然后我在连接条件中添加了“rownum=1”,结果仍然相同。
select * from master t
left join detail d on d.ref_master_id=t.id and rownum=1
最有趣的是,我设置了“rownum<-666”,结果再次得到了相同的结果!
select * from master t
left join detail d on d.ref_master_id=t.id and rownum<-666.
基于结果集,我们可以说在详细表中有3行被判断为“真”。但是如果使用“inner join”,一切都会按照预期进行。
select * from master t
join detail d on d.ref_master_id=t.id and rownum<-666.
这个查询没有返回任何行,因为我无法想象rownum会小于-666 :-)
此外,如果我使用外连接的Oracle语法,使用“(+)”一切都很好。
select * from master m ,detail t
where m.id=t.ref_master_id(+) and rownum<-666.
这个查询也没有返回任何行。
有人能告诉我,我在外连接和rownum方面误解了什么吗?
rank()
函数,例如SELECT *, rank() OVER (ORDER BY d.id) d_rank FROM master m, detail d WHERE d_rank = 1
。然而我不是数据库专家,不知道这会对性能有什么影响。 - Stefan HaberlWITH
CTE、派生表或视图的原因。 - Bill KarwinSELECT * FROM (SELECT *, rank() OVER (ORDER BY d.id) d_rank FROM master m, detail d) WHERE d_rank = 1
(或者像您指出的那样使用WITH
)。 - Stefan Haberl