获取行以在特定条件下交换表

时间:2012-04-22 12:50:05

标签: postgresql inheritance triggers constraints plpgsql

我目前有一个父表:

CREATE TABLE members (
    member_id SERIAL NOT NULL, UNIQUE, PRIMARY KEY
    first_name varchar(20)
    last_name varchar(20)
    address address (composite type)
    contact_numbers varchar(11)[3]
    date_joined date
    type varchar(5)
);

和两个相关的表格:

CREATE TABLE basic_member (
    activities varchar[3])
    INHERITS (members)
);

CREATE TABLE full_member ( 
    activities varchar[])
    INHERITS (members)
);

如果类型为full,则会在full_member表中输入详细信息,或者在basic表中输入basic_member。我想要的是,如果我运行更新并将类型更改为basicfull,则元组将进入相应的表。

我想知道我是否可以通过以下规则来执行此操作:

 CREATE RULE tuple_swap_full
 AS ON UPDATE TO full_member
 WHERE new.type = 'basic'
 INSERT INTO basic_member VALUES (old.member_id, old.first_name, old.last_name,
 old.address, old.contact_numbers, old.date_joined, new.type, old.activities);

...然后从full_member中删除记录

只是想知道我的规则是否在附近,或者是否有更好的方法。

1 个答案:

答案 0 :(得分:1)

  • 您不需要

    member_id SERIAL NOT NULL, UNIQUE, PRIMARY KEY
    

    PRIMARY KEY自动隐含UNIQUE NOT NULL

    member_id SERIAL PRIMARY KEY
    
  • 我不会使用varchar(20)的硬编码最大长度。如果你真的必须强制执行最大长度,只需使用text并添加一个检查约束。更容易改变。

  • INHERITS的语法被破坏了。关键词出现在列周围的parens之外。

    CREATE TABLE full_member ( 
        activities text[]
    ) INHERITS (members);
    
  • 表名不一致(members< - > member)。我在测试用例中到处都使用单数形式。

  • 最后,我不会使用RULE来完成任务。 触发AFTER UPDATE 似乎更可取。

考虑以下

测试用例:

表:

CREATE SCHEMA x;  -- I put everything in a test schema named "x".

-- DROP TABLE x.members CASCADE;
CREATE TABLE x.member (
     member_id SERIAL PRIMARY KEY
    ,first_name text
    -- more columns ...
    ,type text);

CREATE TABLE x.basic_member (
    activities text[3]
) INHERITS (x.member);

CREATE TABLE x.full_member ( 
    activities text[]
) INHERITS (x.member);

触发功能:

Data-modifying CTEsWITH x AS ( DELETE ..)是此目的的最佳工具。需要PostgreSQL 9.1或更高版本 对于旧版本,首先是INSERT,然后是DELETE

CREATE OR REPLACE FUNCTION x.trg_move_member()
  RETURNS trigger AS
$BODY$
BEGIN

CASE NEW.type
WHEN 'basic' THEN
    WITH x AS (
        DELETE FROM x.member
        WHERE member_id = NEW.member_id
        RETURNING *
        )
    INSERT INTO x.basic_member (member_id, first_name, type) -- more columns
    SELECT member_id, first_name, type -- more columns
    FROM   x;

WHEN 'full' THEN
    WITH x AS (
        DELETE FROM x.member 
        WHERE member_id = NEW.member_id
        RETURNING *
        )
    INSERT INTO x.full_member (member_id, first_name, type) -- more columns
    SELECT member_id, first_name, type -- more columns
    FROM   x;
END CASE;

RETURN NULL;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

触发:

请注意,它是AFTER触发器,并且具有WHEN条件。 WHEN条件需要PostgreSQL 9.0或更高版本。对于早期版本,您可以放弃它,触发器中的CASE语句本身可以处理它。

CREATE TRIGGER up_aft
  AFTER UPDATE
  ON x.member
  FOR EACH ROW
  WHEN (NEW.type IN ('basic ','full')) -- OLD.type cannot be IN ('basic ','full')
  EXECUTE PROCEDURE x.trg_move_member();

测试:

INSERT INTO x.member (first_name, type) VALUES ('peter', NULL);

UPDATE x.member SET type = 'full' WHERE first_name = 'peter';
SELECT * FROM ONLY x.member;
SELECT * FROM x.basic_member;
SELECT * FROM x.full_member;