5

最近、いくつかのバグを修正しました。結合条件にrownumがありました。

このようなもの:t1.id=t2.idおよびrownum<2でt1を左結合します。したがって、「左結合」に関係なく、1行のみを返すことになっています。

これをさらに調べてみると、Oracleが「左結合」状態でrownumを評価する方法がわからないことがわかりました。masterとdetailの2つのサンプルテーブルを作成しましょう。

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

結果セットは予測可能です。マスターテーブルのすべての行と、この条件d.ref_master_id=t.idに一致する詳細テーブルの3つの行があります。

結果セット

次に、結合条件に「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行で「True」と評価されたと言えます。しかし、「内部結合」を使用すると、すべてが想定どおりになります。

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.

このクエリは行も返しません。

誰かが私に、アウタージョインとローナムで私が誤解していることを教えてもらえますか?

4

3 に答える 3

8

ROWNUMは、ベーステーブルではなく、結果セットの疑似属性です。ROWNUMは、行が選択された後、ORDERBY句でソートされる前に定義されます。

編集:私は以前のROWNUMの記事で間違っていたので、ここに新しい情報があります:

ROWNUMは、正の整数未満でWHEREあるかどうかをテストするために、句内で限定的に使用できます。詳細については、 ROWNUM疑似列を参照してください。

SELECT ... WHERE ROWNUM < 10

JOIN句のコンテキストでROWNUMがどのような値を持っているかは明確ではないため、結果は未定義である可能性があります。ROWNUMを使用した式には特殊なケースの処理があるようです。たとえば、WHERE ROWNUM > 10常にfalseを返します。ROWNUM<-666JOIN句でどのように機能するかはわかりませんが、意味がないため、使用することはお勧めしません。

いずれの場合も、これは、指定された各マスター行の最初の詳細行をフェッチするのに役立ちません。

これを解決するには、分析関数とを使用し、それを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;
于 2011-07-06T23:15:36.373 に答える
2

結合条件から最初の3つの値を取得する場合は、次のようにselectステートメントを変更します。

    select * 
    from (select * 
          from master t left join detail d on d.ref_master_id=t.id)
    where rownum<3;

必要な出力が得られます。*を使用するときは、明確に定義された列名に注意してください。

コードに変更を加えることなく直接実行できる絶対的な答えを示しましょう。

    select * 
    from (select t.id,t.name,d.id,d.ref_master_id,d.name 
          from master t left join detail d on d.ref_master_id=t.id)
    where rownum<3;
于 2011-07-07T05:48:33.853 に答える
1

ROWNUMフィルターは結合では意味がありませんが、無効として拒否されることはありません。

Explain計画には、ROWNUMフィルターが含まれるか、除外されます。これが含まれている場合は、他の結合条件を適用した後、詳細テーブルにフィルターが適用されます。したがって、ROWNUM = 100(これは決して満たされることはありません)を入力すると、すべての詳細行が除外され、外側の結合が開始されます。

ROWNUM = 1を入れると、フィルターがドロップするようです。

そして、あなたが質問した場合

with 
 a as (select rownum a_val from dual connect by level < 10),
 b as (select rownum*2 b_val from dual connect by level < 10)
select * from a left join b on a_val < b_val and rownum in (1,3);

あなたは完全に奇妙な何かを得る。

おそらくエラーとして拒否されるべきなので、無意味なことが起こることを期待してください

于 2011-07-07T00:47:41.863 に答える