2016-11-17 22 views
4

私は以下のスキーマとデータを持っています。2つのテーブルの間に任意の3番目のテーブルを持つ関係

--drop table table_c; 
--drop table table_b; 
--drop table table_a; 

create table table_a (
    id number(3,0) primary key, 
    value varchar2(10) 
); 

create table table_b (
    id number(3,0) primary key, 
    a_id number(3,0) not null, 
    value varchar2(10), 
    constraint b_fk1 foreign key (a_id) references table_a(id) 
); 

create table table_c (
    id number(3,0) primary key, 
    a_id number(3,0) null, 
    b_id number(3,0) null, 
    value varchar2(10), 
    constraint c_fk1 foreign key (a_id) references table_a(id), 
    constraint c_fk2 foreign key (b_id) references table_b(id) 
); 

-- table a 
insert into table_a (id, value) values (1, 'a'); 
insert into table_a (id, value) values (2, 'b'); 
-- table b 
insert into table_b (id, a_id, value) values (1, 1, 'aa'); 
insert into table_b (id, a_id, value) values (2, 2, 'bb'); 
-- table c with ref to a 
insert into table_c (id, a_id, value) values (1, 1, 'aaa'); 
insert into table_c (id, a_id, value) values (2, 2, 'bbb'); 
-- table c with ref to b 
insert into table_c (id, b_id, value) values (3, 1, 'ccc'); 
insert into table_c (id, b_id, value) values (4, 2, 'ddd'); 
COMMIT; 

我々はtable_cからtable_aへの直接リンクを持っていない場合は、基本的table_atable_bを通るルートとtable_cとの関係です。

table_cの各要素は、a_idまたはb_idのいずれかになります。 a_idがある場合、b_idはありません。 b_idがある場合、a_idはありません。どちらも同時にnullになることはできません。同時にnullでないこともあります。

table_atable_cの関係を示すマテリアライズドビューを作成するように求められました。

私の最初のアイデアは、table_cを更新して、a_idが常に最新であるようにすることでした。顧客はデータベースを強く把握しており、これを禁止します。

--drop materialized view mv_d; 
--drop materialized view log on table_c; 
--drop materialized view log on table_b; 
--drop materialized view log on table_a; 

create materialized view log on table_a with rowid, sequence; 
create materialized view log on table_b with rowid, sequence; 
create materialized view log on table_c with rowid, sequence; 

create materialized view mv_d 
    refresh fast on commit 
    enable query rewrite 
    as 
    select a.value as a_val, 
      c.value as c_val, 
      a.rowid as a_rowid, 
      b.rowid as b_rowid, 
      c.rowid as c_rowid 
     from table_a a, 
      table_b b, 
      table_c c 
    where (c.a_id is null and c.b_id = b.id and b.a_id = a.id) 
     or (c.a_id is not null and c.a_id = a.id); 

execute dbms_stats.gather_table_stats(user, 'mv_d') ; 

このmvの問題は、結果が期待したものではないことです。ここに私が得るものがある。 rowidは相違点と実際の結果を示すために省略されているので、重複する理由を示しています。

select * from mv_d; 

-- note, the rowids are for information only, but are abbreviated to only show how they're different. 
a_val | c_val | a_rowid | b_rowid | c_rowid 
-------+-------+---------+---------+--------- 
a  | aaa | GAAA | WAAA | mAAA 
a  | ccc | GAAA | WAAA | mAAC 
a  | aaa | GAAA | WAAB | mAAA 
b  | bbb | GAAB | WAAA | mAAB 
b  | bbb | GAAB | WAAB | mAAB 
b  | ddd | GAAB | WAAB | mAAD 

理想的には、私は(rowid列、OFCをバー)select * from mv_dから次のような結果を得るだろう。

a_val | c_val 
-------+------- 
a  | aaa 
a  | ccc 
b  | bbb 
b  | ddd 

どのようにしてマテリアライズドビューでその結果を取得できますか?

私の実際のデータベースはtable_a,、table_cのそれぞれ300万件、600万件、100万件の記録であることに注意してください。フィルタリングされたすべての実際の結果は、約10kレコードのマテリアライズド・ビューに存在します。マテリアライズド・ビューの

+0

この古いスタイルのコードを使用してください? – jarlh

+0

@jarlh 1億レコードの中間mv_dでですか?いいえ、私はそれを持つことはできません。問題はマテリアライズド・ビューの問合せにあり、問合せでは発生しません。 –

答えて

4
select  a.value as a_val 
      ,c.value  as c_val 
      ,a.rowid  as a_rowid 
      ,b.rowid  as b_rowid 
      ,c.rowid  as c_rowid 

from     table_a a 

      join  (   table_c c 

         left join table_b b 

         on   c.b_id = b.id 
         ) 

      on   a.id = nvl (b.a_id,c.a_id) 

; 

明確なa_val、mv_d`からc_valを選択し `

select  a.value as a_val 
      ,c.value  as c_val 
      ,a.rowid  as a_rowid 
      ,b.rowid  as b_rowid 
      ,c.rowid  as c_rowid 

from  dmarkovitz.table_a a 
      ,dmarkovitz.table_b b 
      ,dmarkovitz.table_c c 

where  c.b_id = b.id (+) 
     and a.id = nvl (b.a_id,c.a_id) 
; 
+0

私はテストしますが、DBAは結合がマテリアライズド・ビューでは機能しないと主張しました... –

+0

@OlivierGrégoire、編集済みの回答を確認してください –

+0

これは魅力のように機能します!本当にありがとう! –