postgresql:嵌套插入

发布于 2024-11-07 02:27:53 字数 362 浏览 0 评论 0原文

我有两张桌子。让我们说 tblA 和 tblB。
我需要在 tblA 中插入一行,并使用返回的 id 作为要插入到 tblB 中的列之一的值。

我尝试在文档中找到这一点,但无法得到它。 那样编写一条语句(旨在在准备中使用)

INSERT INTO tblB VALUES 
(DEFAULT, (INSERT INTO tblA (DEFAULT, 'x') RETURNING id), 'y')

那么,是否可以像我们为 SELECT 所做的

?或者我应该通过创建存储过程来做到这一点?我不确定是否可以从存储过程中创建准备好的语句。

请指教。

问候,
玛雅克

I have two tables. Lets say tblA and tblB.
I need to insert a row in tblA and use the returned id as a value to be inserted as one of the columns in tblB.

I tried finding out this in documentation but could not get it. Well, is it possible to write a statement (intended to be used in prepared) like

INSERT INTO tblB VALUES 
(DEFAULT, (INSERT INTO tblA (DEFAULT, 'x') RETURNING id), 'y')

like we do for SELECT?

Or should I do this by creating a Stored Procedure?. I'm not sure if I can create a prepared statement out of a Stored Procedure.

Please advise.

Regards,
Mayank

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

潇烟暮雨 2024-11-14 02:27:53

为此,您需要等待 PostgreSQL 9.1:

with
ids as (
insert ...
returning id
)
insert ...
from ids;

同时,您需要在应用程序中使用 plpgsql、临时表或一些额外的逻辑...

You'll need to wait for PostgreSQL 9.1 for this:

with
ids as (
insert ...
returning id
)
insert ...
from ids;

In the meanwhile, you need to use plpgsql, a temporary table, or some extra logic in your app...

暮光沉寂 2024-11-14 02:27:53

这在 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$;

这可以作为单个语句执行。我还没有尝试从中创建一个PreparedStatement。

编辑

另一种方法是简单地分两步进行,首先使用returning子句运行插入到tableA中,通过JDBC获取生成的值,然后触发第二次插入,如下所示:

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();

This is possible with 9.0 and the new DO for anonymous blocks:

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$;

This can be executed as a single statement. I haven't tried creating a PreparedStatement out of that though.

Edit

Another approach would be to simply do it in two steps, first run the insert into tableA using the returning clause, get the generated value through JDBC, then fire the second insert, something like this:

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();
七七 2024-11-14 02:27:53

您可以在两次插入中执行此操作,使用 currval() 检索外键(前提是键是serial):

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)

以这种方式使用 currval 是否安全在交易之内或之外。来自 Postgresql 8.4 文档

电流

返回最近的值
通过该序列的 nextval 获得
在本届会议上。 (一个错误是
如果 nextval 从未存在过则报告
在此调用此序列
会话。)因为这返回一个
会话本地值,它给出了
可预测的答案是否
其他会话已执行nextval
自当前会话以来。

You can do this in two inserts, using currval() to retrieve the foreign key (provided that key is serial):

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;

The result:

select * from tb1a;
 id | t
----+---
  3 | x
(1 row)

select * from tb1b;
 id | tb1a_id | t
----+---------+---
  2 |       3 | y
(1 row)

Using currval in this way is safe whether in or outside of a transaction. From the Postgresql 8.4 documentation:

currval

Return the value most recently
obtained by nextval for this sequence
in the current session. (An error is
reported if nextval has never been
called for this sequence in this
session.) Because this is returning a
session-local value, it gives a
predictable answer whether or not
other sessions have executed nextval
since the current session did.

摘星┃星的人 2024-11-14 02:27:53

您可能需要使用 AFTER INSERT 触发器来实现这一点。 需要类似于:

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();

after insert 的内容,因为您需要有 id 来引用它。希望这有帮助。

编辑

触发器将在与触发它的命令相同的“块”中被调用,即使不使用事务 - 换句话说,它在某种程度上成为该命令的一部分 .. 因此,不存在在插入之间更改引用 id 的风险。

You may want to use AFTER INSERT trigger for that. Something along the lines of:

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();

after insert is needed because you need to have the id to reference it. Hope this helps.

Edit

A trigger will be called in the same "block" as the command that triggered it, even if not using transactions - in other words, it becomes somewhat part of that command.. Therefore, there is no risk of something changing the referenced id between inserts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文