Rownum处于连接状态

Max*_*sov 4 oracle rownum

最近我修复了一些错误:在连接条件下有rownum.

这样的事情:在t1.id = t2.id和rownum <2上左连接t1.因此无论"左连接"如何,它都应该只返回一行.

当我进一步研究这个时,我意识到我不明白Oracle如何在"左连接"条件下评估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.
Run Code Online (Sandbox Code Playgroud)

然后我们有这个查询:

select * from master t
left join detail d on d.ref_master_id=t.id
Run Code Online (Sandbox Code Playgroud)

结果集是可预测的:我们拥有主表中的所有行和详细信息表中与此条件匹配的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
Run Code Online (Sandbox Code Playgroud)

最有趣的是我设置"rownum <-666"并再次得到相同的结果!

select * from master t
left join detail d on d.ref_master_id=t.id and rownum<-666.
Run Code Online (Sandbox Code Playgroud)

由于结果集,我们可以说这个条件在详细信息表中被评估为3行的"真".但如果我使用"内部联接",一切都应该如此.

select * from master t
join detail d on d.ref_master_id=t.id and rownum<-666.
Run Code Online (Sandbox Code Playgroud)

这个查询不返回任何行,因为我无法想象rownum会少于-666 :-)

此外,如果我使用oracle语法进行外连接,使用"(+)"一切都顺利.

select * from master m ,detail t
 where m.id=t.ref_master_id(+) and rownum<-666.
Run Code Online (Sandbox Code Playgroud)

此查询也不返回任何行.

任何人都可以告诉我,我对外连接和rownum的误解是什么?

Bil*_*win 8

ROWNUM是结果集的伪属性,而不是基表的伪属性.ROWNUM是在选择行之后定义的,但是在它们按ORDER BY子句排序之前定义.

编辑:我之前写的ROWNUM错了,所以这里有新的信息:

您可以在WHERE子句中以有限的方式使用ROWNUM ,以测试它是否仅小于正整数.有关详细信息,请参阅ROWNUM Pseudocolumn.

SELECT ... WHERE ROWNUM < 10
Run Code Online (Sandbox Code Playgroud)

目前尚不清楚ROWNUM在JOIN子句的上下文中具有什么值,因此结果可能是未定义的.似乎有一些特殊情况下使用ROWNUM处理表达式,例如WHERE ROWNUM > 10总是返回false.我不知道ROWNUM<-666你的JOIN条款是如何工作的,但它没有意义所以我不建议使用它.

在任何情况下,这都无法帮助您获取每个给定主行的第一个详细信息行.

要解决此问题,您可以使用分析函数PARTITION,并将其与公用表表达式结合使用,以便您可以在其他WHERE条件下访问行号列.

WITH numbered_cte AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY d.something) AS rn
  FROM master t LEFT OUTER JOIN detail d ON d.ref_master_id = t.id
) 
  SELECT *
  FROM numbered_cte
  WHERE rn = 1;
Run Code Online (Sandbox Code Playgroud)