1

考虑表 A 引用表 B 的情况:

create table tableA
(
   id INT NOT NULL PRIMARY KEY,
   information VARCHAR(32)
);
create table tableB
(
   id INT NOT NULL PRIMARY KEY,
   tableAid INT NOT NULL REFERENCES tableA(id),
   other_information VARCHAR(32)
):

请注意,我正在用 Perl 编写代码,并且数据库是 PostgreSQL。

因此,我有 2tableB个条目与单个tableA条目相关联。我想说的是:

use DBI;
my $dbh = DBI->connect("DBI:Pg:dbname=mydb;host=localhost","userid","password",('RaiseError' -> 1));

my $otherinfo = "other info, Table B";
my $moreotherinfo = "more other info, table B";
my info = "table A info";
my $insertitA = $dbh->prepare("insert into tableA (information) values (?)");
my $insertitB = $dbh->prepare("insert into tableB (tableAid,other_information) values (?,?)");
my $nrowsA = $insertitA($info);
my $tableAidreference = ????;
my $nrowsB = $insertitB($tableAidreference, $otherinfo);
my $nrowsB2 = $insertitB($tableAidreference, $moreotherinfo);

我在哪里得到$tableAidreference?我必须搜索tableA它吗?

4

2 回答 2

3

nextval('seq_name')为了后续的目的而单独调用的方法INSERT已经过时并且效率非常低。它需要到服务器的额外往返。不要使用这个。有更好的选择:

-> sqlfiddle

首先,我修改了您的测试设置:

CREATE TABLE tbl_a
(  tbl_a_id serial NOT NULL PRIMARY KEY,
   information text
);
CREATE TABLE tbl_b
(  tbl_b_id serial NOT NULL PRIMARY KEY,
   tbl_a_id int NOT NULL REFERENCES tbl_a(tbl_a_id),
   other_information text
);
  • 不要id用作列名,它不是描述性的。一些不太聪明的 ORM 会这样做,这是一种反模式。

  • 如果可以避免,请勿在 PostgreSQL 中使用混合大小写标识符。

  • 使用serial代理主键的类型。

然后,使用命令的子句在一个数据修改 CTE(需要 PostgreSQL 9.1 或更高版本)中完成所有操作:RETURNINGINSERT

WITH x AS (
    INSERT INTO tbl_a (information)
    VALUES ('foo')
    RETURNING tbl_a_id
    )
INSERT INTO tbl_b (tbl_a_id, other_information)
SELECT tbl_a_id, 'bar'
FROM   x
RETURNING tbl_a_id, tbl_b_id; -- optional, if you want IDs back

往返服务器一次,如果您愿意,您可以取回两个新 ID - 而不是三个往返


如何将它与 DBI 一起使用?

使用 DBD::Pg 模块:

$SQL = q{ WITH x AS (
    INSERT INTO tbl_a (information)
    VALUES (?) 
    RETURNING tbl_a_id
    )
INSERT INTO tbl_b (tbl_a_id, other_information)
SELECT tbl_a_id, 'bar'
FROM   x
RETURNING tbl_a_id, tbl_b_id};
$answer = $dbh->prepare($SQL);
$sth->execute('foo');
$tbl_a_id = $answer->fetch()->[0];
$tbl_b_id = $answer->fetch()->[1];

未经测试。手册中有一个完整的示例DBD::Pg

于 2012-10-16T03:13:41.333 回答
0

这取决于您如何处理主键。通常,您最好的选择是通过从序列中选择值来自己处理增量。如果我们假设tableA.id随着序列递增,那么您可以通过执行如下 SQL 语句从数据库中执行额外的选择:

SELECT NEXTVAL('seq_name'); <-- where seq_name is the name of the sequence you create

您将选择该值,然后使用从数据库中检索到的值id在下面修改后的插入中设置参数:

my $insertitA = $dbh->prepare("insert into tableA (id, information) values (?, ?)");

由于您已明确选择了该值,因此您也可以将其插入到引用表中。

于 2012-10-15T20:56:21.090 回答