postgresql:嵌套插入
我有两张桌子。比如tblA和tblB。postgresql:嵌套插入,postgresql,stored-procedures,prepared-statement,Postgresql,Stored Procedures,Prepared Statement,我有两张桌子。比如tblA和tblB。 我需要在tblA中插入一行,并使用返回的id作为值插入tblB中的一列 我试图在文档中找到这一点,但没有得到它。那么,有没有可能写一个声明(打算在准备中使用)如 就像我们为SELECT做的那样 或者我应该通过创建存储过程来实现这一点?。我不确定是否可以用存储过程创建一个准备好的语句 请告知 问候, Mayank为此,您需要等待PostgreSQL 9.1: with ids as ( insert ... returning id ) insert ...
我需要在tblA中插入一行,并使用返回的id作为值插入tblB中的一列 我试图在文档中找到这一点,但没有得到它。那么,有没有可能写一个声明(打算在准备中使用)如 就像我们为SELECT做的那样 或者我应该通过创建存储过程来实现这一点?。我不确定是否可以用存储过程创建一个准备好的语句 请告知 问候,
Mayank为此,您需要等待PostgreSQL 9.1:
with
ids as (
insert ...
returning id
)
insert ...
from ids;
同时,您需要在应用程序中使用plpgsql、临时表或一些额外的逻辑…这在9.0和新的
DO
中可以用于匿名块:
do $$
declare
new_id integer;
begin
insert into foo1 (id) values (default) returning id into new_id;
insert into foo2 (id) values (new_id);
end$$;
这可以作为单个语句执行。不过,我还没有试着用它来创建一个准备好的声明
编辑另一种方法是分两步完成,首先使用returning子句将insert运行到tableA中,通过JDBC获取生成的值,然后启动第二个insert,如下所示:
PreparedStatement stmt_1 = con.prepareStatement("INSERT INTO tblA VALUES (DEFAULT, ?) returning id");
stmt_1.setString(1, "x");
stmt_1.execute(); // important! Do not use executeUpdate()!
ResultSet rs = stmt_1.getResult();
long newId = -1;
if (rs.next()) {
newId = rs.getLong(1);
}
PreparedStatement stmt_2 = con.prepareStatement("INSERT INTO tblB VALUES (default,?,?)");
stmt_2.setLong(1, newId);
stmt_2.setString(2, "y");
stmt_2.executeUpdate();
您可能希望在插入后使用
触发器。大致如下:
create function dostuff() returns trigger as $$
begin
insert into table_b(field_1, field_2) values ('foo', NEW.id);
return new; --values returned by after triggers are ignored, anyway
end;
$$ language 'plpgsql';
create trigger trdostuff after insert on table_name for each row execute procedure dostuff();
插入后需要,
,因为您需要有引用它的id。希望这有帮助
编辑
触发器将在与触发它的命令相同的“块”中调用,即使不使用事务——换句话说,它在某种程度上成为该命令的一部分。。因此,不存在在插入之间更改引用id的风险。您可以在两次插入中执行此操作,使用
currval()
检索外键(前提是键是串行的):
结果是:
select * from tb1a;
id | t
----+---
3 | x
(1 row)
select * from tb1b;
id | tb1a_id | t
----+---------+---
2 | 3 | y
(1 row)
无论是在事务内部还是外部,以这种方式使用currval都是安全的。从:
柯尔瓦尔
返回最近的值
由nextval为此序列获取
在本届会议上。(错误是
如果nextval从未被
在本例中调用此序列
会话。),因为这将返回
会话本地值,它给出一个
可预测的答案是否
其他会话已执行nextval
自本届会议以来
也许我是个偏执狂,但依靠
currval
不是最好的主意。首先,它假定id基于序列。其次,除非显式使用事务,否则键的值可能会在插入之间发生变化,这会破坏完整性。第三,它是不可重用的。但是,这只是我的观点,你不必同意:)@sary,我编辑了答案,以解决你对钥匙价值的担忧。对于其他指控,我请求诺洛申辩。@Waynce,你的编辑澄清了这个问题。因此,我的评论现在应该指出“依赖currval
是一个很好的选择,只要id绑定到序列”。尽管第三个问题仍然存在,但这是一个设计问题,不包括在问题中,可能会引发一场无休止的辩论,所以最好到此为止。@悲伤,我同意,它完全不可移植。无论如何,谢谢你帮助我把答案做得更好。
create temporary table tb1a (id serial primary key, t text);
create temporary table tb1b (id serial primary key,
tb1a_id int references tb1a(id),
t text);
begin;
insert into tb1a values (DEFAULT, 'x');
insert into tb1b values (DEFAULT, currval('tb1a_id_seq'), 'y');
commit;
select * from tb1a;
id | t
----+---
3 | x
(1 row)
select * from tb1b;
id | tb1a_id | t
----+---------+---
2 | 3 | y
(1 row)