(Примечание. Обновлены с принятой ответ ниже)PostgreSQL: UPDATE подразумевает перемещение по разделам
Для 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
триггер и функции работают хорошо: новые активные записи будут положить в одну таблице, и новая неактивные записи в другой. Я хотел бы, чтобы UPDATE
s в поле ACTIVE, чтобы «переместить» запись из одной таблицы потомков в другую, но встречаю ошибку, которая предполагает, что это может быть невозможно.
Trigger спецификация и сообщение об ошибке:
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/ОТВЕТ
Ниже процедура 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, thanks - cut'n'paste ошибки. Будет исправлено. – pilcrow
Какой смысл использовать раздел в этом контексте, если вы можете использовать частичный индекс? – kalu