Oracle Insert Into Child&父表

时间:2013-11-19 23:18:55

标签: oracle insert

我有一张桌子 - 我们称之为MASTER - 里面有很多行。现在,我不得不创建另一个名为“MASTER_DETAILS”的表,该表将填充来自另一个系统的数据。 Suh数据将通过DB Link访问。

MASTER具有到MASTER_DETAIL的FK(1 - > 1关系)。

我创建了一个SQL来填充MASTER_DETAILS表:

INSERT INTO MASTER_DETAILS(ID, DETAIL1, DETAILS2, BLAH)
    WITH QUERY_FROM_EXTERNAL_SYSTEM AS (
       SELECT IDENTIFIER,
              FIELD1,
              FIELD2,
              FIELD3
       FROM TABLE@DB_LINK 
       --- DOZENS OF INNERS AND OUTER JOINS HERE
    ) SELECT MASTER_DETAILS_SEQ.NEXTVAL, 
             QES.FIELD1, 
             QES.FIELD2, 
             QES.FIELD3
      FROM MASTER M
      INNER JOIN QUERY_FROM_EXTERNAL_SYSTEM QES ON QES.IDENTIFIER = M.ID
      --- DOZENS OF JOINS HERE

上述方法可以很好地将所有值插入MASTER_DETAILS。

问题是:

在上面的方法中,我无法将MASTER_DETAILS_SEQ.CURRVAL的值插入MASTER表中。所以我在DETAILS表中创建了所有条目,但是我没有将它们链接到MASTER表。

有没有人只使用INSERT语句就能找到解决这个问题的方法?我希望我能避免使用LOOPS创建一个复杂的脚本以及处理这个问题的所有内容。

理想情况下,我想做这样的事情:

  INSERT INTO MASTER_DETAILS(ID, DETAIL1, DETAILS2, BLAH) AND MASTER(MASTER_DETAILS_ID)
    WITH QUERY_FROM_EXTERNAL_SYSTEM AS (
       SELECT IDENTIFIER,
              FIELD1,
              FIELD2,
              FIELD3
       FROM TABLE@DB_LINK 
       --- DOZENS OF INNERS AND OUTER JOINS HERE
    ) SELECT MASTER_DETAILS_SEQ.NEXTVAL, 
             QES.FIELD1, 
             QES.FIELD2, 
             QES.FIELD3
      FROM MASTER M
      INNER JOIN QUERY_FROM_EXTERNAL_SYSTEM QES ON QES.IDENTIFIER = M.ID
      --- DOZENS OF JOINS HERE,
      SELECT MASTER_DETAILS_SEQ.CURRVAL FROM DUAL; 

我知道这种方法对Oracle不起作用 - 但是我正在展示这个SQL来演示我想要做的事情。

感谢。

1 个答案:

答案 0 :(得分:1)

如果两个表之间确实存在一对一的关系,那么它们可以说是一个表。大概你有理由想要将它们分开。也许主人是供应商提供的表,你不应该触摸,细节是额外的数据;但是你要通过添加外键字段来改变主人。或者可能会定期重新加载详细信息,您不希望更新主表;但无论如何你必须更新外键字段。无论出于何种原因,我都会假设你需要一张单独的桌子。

如果在主表上放置一个引用详细信息表上主键的外键,则只能将其作为一对一关系限制。如果确实如此,那么从概念上讲,关系的构建方式无关紧要 - 哪个表具有主键,哪个表具有外键。如果不是,那么当您的详细信息表(或远程查询)返回与同一主人相关的两行时,您的模型将会中断 - 即使您确定今天不会发生这种情况,它始终是真的?名称master_details的复数表明可能会出现这种情况。也许。以另一种方式建立关系可以防止这是一个问题。

我猜你决定把这种关系放在一边,这样你就可以使用细节键加入表格了:

select m.column, md.column
from master m
join master_details md on md.id = m.detail_id

...因为您希望这是最快捷的方式,因为md.id将被编入索引(隐式地,作为主键)。但是,您可以通过将主ID作为外键添加到详细信息表中来实现相同的效果:

select m.column, md.column
from master m
join master_details md on md.master_id = m.id

最好将外键编入索引,只要你在master_details.master_id上有一个索引,那么性能应该是相同的(或多或少,其他因素可能会起作用但我会期望通常情况如此)。这也将允许将来使用多个详细记录,而无需修改架构。

举一个简单的例子,假设您创建了一个主表并填充了一些虚拟数据:

create table master(id number, data varchar2(10),
  constraint pk_master primary key (id));

create sequence seq_master start with 42;

insert into master (id, data)
values (seq_master.nextval, 'Foo ' || seq_master.nextval);
insert into master (id, data)
values (seq_master.nextval, 'Foo ' || seq_master.nextval);
insert into master (id, data)
values (seq_master.nextval, 'Foo ' || seq_master.nextval);

select * from master;

        ID DATA     
---------- ----------
        42 Foo 42    
        43 Foo 43    
        44 Foo 44    

您提出的更改可能如下所示:

create table detail (id number, other_data varchar2(10),
  constraint pk_detail primary key(id));

create sequence seq_detail;

alter table master add (detail_id number,
  constraint fk_master_detail foreign key (detail_id) 
    references detail (id));

insert into detail (id, other_data)
select seq_detail.nextval, 'Foo ' || seq_detail.nextval
from master m
-- joins etc
;

...再加上主人外键的更新,这就是你正在努力解决的问题,所以现在让我们手动执行:

update master set detail_id = 1 where id = 42;
update master set detail_id = 2 where id = 43;
update master set detail_id = 3 where id = 44;

然后你会查询:

select m.data, d.other_data
from master m
join detail d on d.id = m.detail_id
where m.id = 42;

DATA       OTHER_DATA
---------- ----------
Foo 42     Bar 1      

Plan hash value: 2192253142

------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |     1 |    22 |     2   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |           |     1 |    22 |     2   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| MASTER    |     1 |    13 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_MASTER |     1 |       |     0   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| DETAIL    |     3 |    27 |     1   (0)| 00:00:01 |
|*  5 |    INDEX UNIQUE SCAN         | PK_DETAIL |     1 |       |     0   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

如果您更改关系,则更改将变为:

create table detail (id number, master_id, other_data varchar2(10),
  constraint pk_detail primary key(id),
  constraint fk_detail_master foreign key (master_id)
    references master (id));

create index ix_detail_master_id on detail (master_id);

create sequence seq_detail;

insert into detail (id, master_id, other_data)
select seq_detail.nextval, m.id, 'Bar ' || seq_detail.nextval
from master m
-- joins etc.
;

不需要更新主表,查询变为:

select m.data, d.other_data
from master m
join detail d on d.master_id = m.id
where m.id = 42;

DATA       OTHER_DATA
---------- ----------
Foo 42     Bar 1      

Plan hash value: 4273661231

----------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                     |     1 |    19 |     2   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |                     |     1 |    19 |     2   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| MASTER              |     1 |    10 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_MASTER           |     1 |       |     0   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| DETAIL              |     1 |     9 |     1   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN          | IX_DETAIL_MASTER_ID |     1 |       |     0   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------

计划中唯一真正的区别是你现在有一个范围扫描而不是一个独特的扫描;如果你真的确定它是1比1你可以使索引独特,但没有太大的好处。

SQL Fiddle这种方法。