Триггер вставки postgresql для установки значения

Предположим, в Postgresql у меня есть таблица T, а один из ее столбцов - C1.

Я хочу вызвать функцию, когда в таблицу добавляется новая запись T. Функция должна проверить значение столбца C1 в новой записи и, если он пустой / пустой, установить его значение на 'X'.

Это возможно?


person user1408470    schedule 19.04.2013    source источник
comment
Пожалуйста, обратите внимание, что это значение X необходимо получить из другого подзапроса.   -  person user1408470    schedule 19.04.2013


Ответы (2)


Вы правы, что вам нужен триггер, потому что установка значения по умолчанию для столбца не сработает для вас - значения по умолчанию работают только для null значений и не помогут вам предотвратить пустые значения.

В postgres есть пара шагов для создания триггера:

Шаг 1. Создайте функцию, возвращающую тип trigger:

CREATE FUNCTION my_trigger_function()
RETURNS trigger AS '
BEGIN
  IF NEW.C1 IS NULL OR NEW.C1 = '''' THEN
    NEW.C1 := ''X'';
  END IF;
  RETURN NEW;
END' LANGUAGE 'plpgsql'

Шаг 2. Создайте триггер, который срабатывает перед вставкой, что позволяет вам изменять значения до их вставки, вызывая указанную выше функцию:

CREATE TRIGGER my_trigger
BEFORE INSERT ON T
FOR EACH ROW
EXECUTE PROCEDURE my_trigger_function()

И вы сделали.

См. приведенный выше код, выполняющийся на SQLFIddle, демонстрирующий его правильную работу!


Вы упоминаете в комментарии, что значение 'X' извлекается из подзапроса. Если да, измените соответствующую строку примерно так:

NEW.C1 := (select some_column from some_table where some_condition);
person Bohemian♦    schedule 19.04.2013
comment
Спасибо за ответ. Это именно то, что я хотел. - person user1408470; 20.04.2013
comment
Почему вы не используете $$, а вместо этого '? - person Stefan Falk; 21.02.2016
comment
@StefanFalk Одна из возможных причин заключается в том, что программное обеспечение, такое как DbVisualizer, имеет проблемы с разделителями с $$. Все это время меня лишали возможности использовать функции, пока вы не указали на это! - person Noumenon; 24.05.2018
comment
если вам не нравится IF, вы можете использовать одну строку с coalesce (), например: new.c1 := coalesce (new.c1,X); - person Bernardo Jerez; 06.11.2018

Это возможно, но вам, вероятно, будет лучше вместо этого установить ограничение по умолчанию для столбца. При создании таблицы она будет выглядеть так:

create table mytable as (
    C1 thetype not null default X
);

Это говорит о том, что если вы добавите строку в таблицу и не укажете значение для C1, вместо этого будет использоваться X. Нулевое значение не является обязательным, но не позволяет обновлениям обнулять этот столбец, если вы этого хотите.

РЕДАКТИРОВАТЬ: это работает только для постоянного X, из ваших комментариев кажется, что есть два возможных решения.

Использование триггера будет выглядеть примерно так:

create function update_row_trigger() returns trigger as $$
begin
    if new.C1 is NULL then
        new.C1 := X;
    end if;
    return new;
end
$$ language plpgsql;

create trigger mytrigger before insert on mytable for each row execute procedure update_row_trigger();

Переменная new в функции триггера является специальной, представляя вставляемую строку. Указание триггера как триггера before insert означает, что вы можете изменить строку до того, как она будет записана в таблицу.

Второе решение - использовать вычисляемый столбец, который Postgres определяет необычным образом:

create or replace function C1(row mytable) returns columntype immutable as $$
begin
    return X; -- where X is an expression using values from `row`
end
$$ language plpgsql;

Это создает функцию, которая берет строку вашей таблицы и возвращает значение, которое вы можете вызвать с помощью. обозначения, что означает, что вы можете:

select
    *,
    t.C1
from
    mytable t;

Объявление неизменяемой функции необязательно, но оно необходимо, если вы хотите проиндексировать «столбец». Вы можете проиндексировать этот столбец следующим образом:

create index on mytable (C1(mytable));
person Steve    schedule 19.04.2013
comment
Спасибо, но в моем случае я получаю сообщение об ошибке при установке значения в качестве ограничения по умолчанию. Поскольку это значение X получается подзапросом, это недопустимо. Подскажите, пожалуйста, обходной путь. - person user1408470; 19.04.2013
comment
Однозначно ли значение C1 определяется другими значениями в той же строке или зависит от других факторов, таких как время дня или данные в других таблицах? - person Steve; 19.04.2013
comment
Это однозначно определено. просто он извлекается с помощью (выберите идентификатор из таблицы 2, где name = 'Unique_Value'). Этот идентификатор может отличаться в разных БД, поэтому всегда нужно получать его из подзапроса. - person user1408470; 19.04.2013