在表中插入数据,在一个查询中使用 FK 更新其他表

Posted

技术标签:

【中文标题】在表中插入数据,在一个查询中使用 FK 更新其他表【英文标题】:Insert data in table, update other table with FK in one query 【发布时间】:2017-12-13 12:07:49 【问题描述】:

我有一个具有 3 个属性的表 A:

ID (PK)、UNIT(varchar2)、VALUE(数字)

我还有另一个表 B,它通过外键引用表 A 的 PK。

ID,FK_TABLE_A

表 B 中已有记录,但属性 FK_TABLE_A 的值为空。我想要的是,表 B 中的所有记录通过将新数据插入表 A 并将新创建的主键作为外键引用到表 B 中来获得对表 A PK 的自己的唯一引用。 p>

到目前为止我做了什么: 我现在可以通过以下 SQL 插入新数据:

INSERT INTO TABLE_A(ID, UNIT, VALUE) VALUES (TABKE_A_SEQ.nextval, 'SOME_STRING', 1);

我可以手动更新对表 B 的引用

UPDATE TABLE_B SET FK_TABLE_A = 123; //123 is just an example PK

但我不想在每次数据库时都查询每条记录,而是想以某种方式将第一个 insert 与第二个 update 组合在一个查询中。 以便更新以表 A 中新创建的 PK 作为参考。

这可能吗?

我使用 Oracle 作为数据库。

【问题讨论】:

您的意思是在更新中使用TABKE_A_SEQ.currval 而不是123?如果还没有 PK/FK 关系,如何知道要更新表 B 中的哪些行? 您的 TABLE_B 正在引用 TABLE_A。你怎么知道要更新哪个子行?如果是TABLE_A中的insert,也应该是TABLE_B中的insert,而不是update。 Table_B 中的每条记录当然应该得到不同的外键。 (这是表A中新创建的条目的主键) 【参考方案1】:

在会话中使用序列后,您可以通过use the currval pseudocolumn 获取会话中发出的最后一个序列值,通过最后一次nextval 调用:

INSERT INTO TABLE_A(ID, UNIT, VALUE) VALUES (TABKE_A_SEQ.nextval, 'SOME_STRING', 1);
UPDATE TABLE_B SET FK_TABLE_A = TABKE_A_SEQ.currval;

(虽然您没有过滤器,但它会将表 B 中的所有行更新为相同的 FK 值;可能您正在做一些更复杂的事情来识别相关行...)


如果您想要一个一对一的关系并且不关心哪一行获得哪个 PK 值,并且您可以使约束可延迟,您可以反过来处理它;使用序列更新所有表 B 行,然后使用这些行创建表 A 行。

使用快速演示表:

create table table_a (id number primary key, unit varchar2(20), value number);
create table table_b (id number,
  fk_table_a number references table_a(id) initially deferred deferrable);
create sequence table_a_seq;
create sequence table_b_seq start with 50;

insert into table_b (id) select table_b_seq.nextval from dual connect by level <= 5;

然后,在单个事务中,更新所有行并执行单个插入:

update table_b set fk_table_a = table_a_seq.nextval;

insert into table_a (id, unit, value)
select fk_table_a, 'SOME_STRING', 1
from table_b;

约束必须是可延迟的,以允许更新首先发生;否则你会得到 ORA-02291。

如果单位/值来自table_a,您可以将它们包含在查询中,而不是使用固定文字。很难说你真正需要什么,你说他们甚至可以留空。

现在你有:

select * from table_a;

        ID UNIT                      VALUE
---------- -------------------- ----------
         1 SOME_STRING                   1
         2 SOME_STRING                   1
         3 SOME_STRING                   1
         4 SOME_STRING                   1
         5 SOME_STRING                   1

select * from table_b;

        ID FK_TABLE_A
---------- ----------
        50          1
        51          2
        52          3
        53          4
        54          5

【讨论】:

这只会在 Table_A 中创建一个条目。我想为表 B 中的每条记录在表 A 中创建一个新条目,并从 TABLE_B 中的 TABLE_A 引用这个新创建的 PK 您如何决定表 B 中的哪些行获得哪个 PK/FK 值?您是否将表 B 中的值拉出到单独的表中并想参考该值? (例如 B 中当前存在单位和值但重复?)你也让它听起来像一对一的关系;如果是这样,为什么要将数据拆分到两个表中? 是的,这是一对一的关系。我决定拆分它,因为 TABLE_B 已经有很多属性(并且 TABLE B 没有明确使用)。 Table_B应该得到表A中已创建条目的立即创建的PK值,这就是我想到一次性命令的原因:) OK.. 那么单位和值是从哪里来的,它们现在是表 B 中的列吗? 您可以将这些值保留为空,或保留为虚拟值。我只对创建的PK感兴趣。【参考方案2】:

使用触发器(在 TABLE_A 上)在 TABLE_B 中创建行。

例如(假设您使用 SEQUENCE 生成 PK)

 CREATE OR REPLACE TRIGGER TR_TABLE_A_AI
 AFTER INSERT
 ON TABLE_A
 FOR EACH ROW
BEGIN
  INSERT INTO TABLE_B VALUES (SEQ_TABLE_B.NEXTVAL, :NEW.ID);
END;

【讨论】:

我只想做一次,作为迁移脚本的一部分,而不是永久的。

以上是关于在表中插入数据,在一个查询中使用 FK 更新其他表的主要内容,如果未能解决你的问题,请参考以下文章

oracle触发器在表中插入新行时更新新的视图行

如何向表中插入数据以及如何更新删除表中的数据

查询联结表中FK引用的表中的其他字段

Python & Bigquery:使用 for 循环在表中逐行查询和插入数据

每次在表中插入后根据查询结果发送电子邮件 - Talend

MySQL 从分配自动增量 ID 的表插入并更新第三个表中的 FK