PostgreSQL 的规则和 nextval()/串行问题(非常 PostgreSQL 特定)

2024-02-25

当我使用重写规则将一个表中的插入拆分为对其他两个表的插入时,其中插入的值之一具有默认的 nextval('some_sequence') ,两个表的序列相同,则插入的默认值在两张桌子。这可能是由于重写规则的简单文本替换所致。相反,我希望首先解析默认值,然后将相同的值写入两个表。

这是一个示例(正如您可能猜到的那样,我正在尝试使用规则来实现专业化/泛化):

-- 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".

解决此问题的一种方法是将重写规则的第二次插入替换为

insert into Partial_Children1(id, attribute2, type)
  select p.id, new.attribute2, p.type
    from Parents p
    where p.attribute1 = new.attribute1

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

有谁知道如何在两个表中获得相同的默认值(仅使用规则和not触发器)?


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

它(规则系统)修改查询 考虑规则,并且 然后将修改后的查询传递给 查询规划器用于规划和 执行

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

当您不一次插入多条记录时,您可以使其工作:

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

but not

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

因此,您确实不应该将规则系统与棘手的 currval() 调用一起使用。

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

  • http://www.postgresql.org/docs/8.2/interactive/rules-update.html http://www.postgresql.org/docs/8.2/interactive/rules-update.html
  • http://archives.postgresql.org/pgsql-sql/2004-10/msg00195.php http://archives.postgresql.org/pgsql-sql/2004-10/msg00195.php
  • http://archives.postgresql.org/pgsql-general/2009-06/msg00278.php http://archives.postgresql.org/pgsql-general/2009-06/msg00278.php

另一个提示:postgresql 邮件列表的支持与数据库引擎本身一样出色!

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

  • http://www.postgresql.org/docs/8.4/interactive/ddl-inherit.html http://www.postgresql.org/docs/8.4/interactive/ddl-inherit.html

摘要:您应该使用触发器或避免多行插入!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PostgreSQL 的规则和 nextval()/串行问题(非常 PostgreSQL 特定) 的相关文章

随机推荐