PostgreSQL триггеры, как реагировать на изменние значения в определённой колонке
Частый кейс в работе, это настройка уведомлений или других действий, когда данные изменили оригинальное значение. Например, ваши данные обновляются по крону из стороннего API и вы делаете массовую вставку в БД через update
или upsert
, что бы сэкономить ресурсы. Но в таком случае вы не можете на стороне вашего приложения отслеживать изменения. На помощь приходит, как всегда сам PostgreSQL. В PostgreSQL есть такие фишки, как триггеры и функции.
Давайте рассмотрим на примере моего проекта. У меня есть таблица leads
, содержащая информацию о потенциальных клиентах. Я хочу отслеживать изменения в столбце статус, который показывает, был ли лид автоматически назначен продавцу или нет. Каждый раз, когда колонка статуса обновляется с одного значение на другое, я хочу создавать новую запись в отдельной таблице status_log
, которая содержит текущее время и новое значение статуса.
На основе таблицы status_log
можно будет отображать историю изменений или отправлять уведомления на почту, телеграм итд.
Для начала нам понадобится функция на предмет изменения в колонке статуса и триггер который её запустит.
Функция
В вашей системе управления БД выполните код который создаст новую функцию log_lead_status_changes
. Где условие IF NEW.status <> OLD.status THEN
отслеживает произошло ли изменение колонки status
:
CREATE OR REPLACE FUNCTION log_lead_status_changes()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.status <> OLD.status THEN -- only log changes
INSERT INTO status_log (lead_id, time, new_status)
VALUES (NEW.id, now(), NEW.status);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Триггер
Теперь осталось создать триггер, который будет вызывать нашу функцию:
CREATE TRIGGER lead_status_change
AFTER UPDATE OF status ON leads
FOR EACH ROW
EXECUTE FUNCTION log_lead_status_changes();
Вот и вся магия. Не забудьте создать вашу таблицу status_log
куда будут записываться все изменения. Пример:
CREATE TABLE status_log (
id SERIAL PRIMARY KEY,
lead_id INTEGER NOT NULL REFERENCES leads(id),
time TIMESTAMP NOT NULL DEFAULT now(),
new_status VARCHAR(255) NOT NULL
);
Теперь вы можете написать в своем бэкенде простую очередь, которая будет проверять таблицу status_log
и отправлять уведомления об изменениях. А затем удалить запись из таблицы журнала.