【发布时间】:2010-12-20 08:54:34
【问题描述】:
(注意:已更新以下采用的答案。)
对于 PostgreSQL 8.1(或更高版本)分区表,如果 UPDATE 意味着对受约束字段的更改,如何定义 UPDATE 触发器和过程以将记录从一个分区“移动”到另一个分区定义分区隔离?
例如,我有一个表记录分区为活动和非活动记录,如下所示:
create table RECORDS (RECORD varchar(64) not null, ACTIVE boolean default true);
create table ACTIVE_RECORDS ( check (ACTIVE) ) inherits RECORDS;
create table INACTIVE_RECORDS ( check (not ACTIVE) ) inherits RECORDS;
INSERT 触发器和函数运行良好:新的活动记录放在一个表中,新的非活动记录放在另一个表中。我希望 UPDATEs 到 ACTIVE 字段以将记录从一个后代表“移动”到另一个,但遇到一个错误,表明这可能是不可能的。
触发器规范和错误信息:
pg=> CREATE OR REPLACE FUNCTION record_update()
RETURNS TRIGGER AS $$
BEGIN
IF (NEW.active = OLD.active) THEN
RETURN NEW;
ELSIF (NEW.active) THEN
INSERT INTO active_records VALUES (NEW.*);
DELETE FROM inactive_records WHERE record = NEW.record;
ELSE
INSERT INTO inactive_records VALUES (NEW.*);
DELETE FROM active_records WHERE record = NEW.record;
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
pg=> CREATE TRIGGER record_update_trigger
BEFORE UPDATE ON records
FOR EACH ROW EXECUTE PROCEDURE record_update();
pg=> select * from RECORDS;
record | active
--------+--------
foo | t -- 'foo' record actually in table ACTIVE_RECORDS
bar | f -- 'bar' record actually in table INACTIVE_RECORDS
(2 rows)
pg=> update RECORDS set ACTIVE = false where RECORD = 'foo';
ERROR: new row for relation "active_records" violates check constraint "active_records_active_check"
使用触发器过程(返回 NULL 等)向我表明,在调用触发器之前检查了约束并引发了错误,这意味着我当前的方法不起作用。这可以工作吗?
更新/回答
下面是我最终使用的UPDATE 触发程序,分配给每个分区的程序相同。完全归功于Bell,他的回答让我获得了触发分区的关键见解:
CREATE OR REPLACE FUNCTION record_update()
RETURNS TRIGGER AS $$
BEGIN
IF ( (TG_TABLE_NAME = 'active_records' AND NOT NEW.active)
OR
(TG_TABLE_NAME = 'inactive_records' AND NEW.active) ) THEN
DELETE FROM records WHERE record = NEW.record;
INSERT INTO records VALUES (NEW.*);
RETURN NULL;
END IF;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
【问题讨论】:
-
您的“示例”不完整:缺少“partitioned_records”的定义;您为“partitioned_records”定义触发器,但从“RECORDS”中选择并更新。
-
@Milen,谢谢——剪切粘贴错误。会补救。
-
当您可以使用部分索引时,在这种情况下使用分区有什么意义?
标签: postgresql triggers partitioning