PostgreSQL的规则和nextval()/序列问题(非常PostgreSQL特定的)

问题描述:

当我使用一个重写规则,将插入到一个表中插入到其他插入值之一作为默认nextval('some_sequence '),这两个表的插入默认值是不同的。这可能是由于重写规则简单的文本替换。我曾希望首先解决默认值,然后将相同的值写入这两个表中。PostgreSQL的规则和nextval()/序列问题(非常PostgreSQL特定的)

下面一个例子(因为你可能已经猜到,我试图实现使用规则专业化/一般化):

-- first and third commands can be skipped if id is defined as serial 
create sequence parents_id_seq; 
create table Parents(
    id integer default(nextval('parents_id_seq')) primary key, 
    type varchar(50) not null check(type in ('Child1', 'Child2')), 
    unique (id, type), 
    attribute1 varchar(50) not null unique check(length(attribute1) > 0) 
); 
alter sequence parents_id_seq owned by parents.id; 

具体到第一类儿童被关在

create table Partial_Children1(
    id integer default(nextval('parents_id_seq')) primary key, 
    type varchar(50) not null check(type = 'Child1'), 
    foreign key (id, type) references Parents(id, type), 
    attribute2 varchar(50) not null check(length(attribute2) > 0) 
); 
数据

接下来我定义了一个视图Children1,它连接上面的两个表(我通过明确指出PostgreSQL根据文档定义视图来重写视图)

create table Children1(
    id int default(nextval('parents_id_seq')), 
    type varchar(50) not null check(type in ('Child1')), 
    attribute1 varchar(50) not null check(length(attribute1) > 0), 
    attribute2 varchar(50) not null check(length(attribute2) > 0) 
); 
create rule "_RETURN" as on select to Children1 do instead 
    select p.*, c.attribute2 
    from Parents p 
    join Partial_Children1 c 
     on p.id = c.id; 

与最后我有重写规则问题:

create rule ct_i_children1 as 
    on insert to Children1 
    do instead (
    insert into Parents(attribute1, type) 
     values(new.attribute1, 'Child1'); 
    insert into Partial_Children1(attribute2, type) 
     values(new.attribute2, 'Child1'); 
); 

试图与

insert into Children1 (attribute1, attribute2) 
    values ('a1', 'a2'), 
     ('b1', 'b2'); 

插入数据产生的错误信息

ERROR: insert or update on table "partial_children1" violates foreign key constraint "partial_children1_id_fkey" 
DETAIL: Key (id,type)=(3,Child1) is not present in table "parents". 

解决这种情况的方法正在用

取代重写规则的第二个插入3210
insert into Partial_Children1(id, attribute2, type) 
    select p.id, new.attribute2, p.type 
    from Parents p 
    where p.attribute1 = new.attribute1 

但这依赖于属性1的独特性,我不想强​​加它。另一种解决方案是先将值插入临时表中,然后从中选择两次以插入两个表中。但由于性能原因,我不喜欢它。

有没有人有另一种想法如何在两个表中获得相同的默认值(只使用规则和而不是触发器)?

从文档 http://www.postgresql.org/docs/8.4/static/rules.html

它(规则系统)查询修改 到需要考虑规则和 然后通过修改后的查询到 查询规划计划和 执行

因此它首先重写查询而不执行任何操作。

你可以当你不一次插入multipe记录它的工作:

create or replace rule ct_i_children1 as 
    on insert to Children1 
    do instead (
    insert into Parents(id, attribute1, type) 
     values(nextval('parents_id_seq'), new.attribute1, 'Child1'); 
    insert into Partial_Children1(id, attribute2, type) 
     values(currval('parents_id_seq'), new.attribute2, 'Child1'); 
); 

然后,你可以这样做:

insert into Children1 (attribute1, attribute2) values ('a1', 'a2'); 
insert into Children1 (attribute1, attribute2) values ('b1', 'b2'); 

但不

insert into Children1 (attribute1, attribute2) 
    values ('a1', 'a2'), 
     ('b1', 'b2'); 

所以,你真的不应该使用具有棘手currval()调用的规则系统。

另外看看在这些页面的评论:

另一个秘诀:在PostgreSQL的邮件列表的支持是优秀的数据库引擎本身!

顺便说一下:你知道postgresql支持开箱即用的继承吗?

总结:你应该使用触发器或避免多次行插入!

+0

感谢您的链接。他们没有解决问题,但至少我不再孤单了---)。 内置的继承没有完全提供我想要的。 – 2010-07-16 17:05:33

规则会为你做 - 它们在执行前重写查询。

只要你有一个实际的基表(Children1),我认为你可以用TRIGGER而不是RULE完成同样的事情。

+0

对不起,您是否完全读过我的问题? – 2009-08-28 20:04:22

+0

恩,我以为我做到了。但我想我至少错过了“不触发”部分,对此感到遗憾。 – 2009-08-28 21:19:00

+0

而规则给出了错误的结果;-)。 – 2009-08-30 17:31:30