Обновляемые представления и триггеры INSTEAD OF
Делайте представления непосредственно обновляемыми или используйте триггеры INSTEAD OF, когда представление агрегирует или объединяет данные
«Обновляемые представления и триггеры INSTEAD OF» — бесплатный урок SQL Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Academy содержит 4 уроков всего.
Автоматически изменяемые представления
PostgreSQL автоматически делает простые представления изменяемыми. Операции INSERT/UPDATE/DELETE над представлением переписываются в такие же операции над базовой таблицей:
CREATE VIEW active_users AS
SELECT id, email, full_name FROM users WHERE deleted_at IS NULL;
UPDATE active_users SET full_name = 'Alice' WHERE id = 1;
-- Translates to UPDATE on the users table.Требования для автоматического обновления
Представление должно:
- Ссылаться ровно на одну базовую таблицу — ONE
- Не содержать агрегатов, GROUP BY, HAVING, DISTINCT
- Не содержать LIMIT, OFFSET
- Не содержать операций над множествами (UNION и т. д.)
- Напрямую отображать столбцы (без выражений в списке SELECT — или только с некоторыми исключениями)
WITH CHECK OPTION
Запрещает записи, из-за которых строки стали бы невидимыми в представлении:
CREATE VIEW active_users AS
SELECT * FROM users WHERE deleted_at IS NULL
WITH CHECK OPTION;
INSERT INTO active_users (email, deleted_at) VALUES (..., NOW());
-- ERROR — would create a row outside the view's WHERE.Для сложных представлений нужен INSTEAD OF
Представления с объединениями, агрегатами или выражениями не обновляются автоматически. Необходимо написать триггер INSTEAD OF, который определяет смысл операции записи:
CREATE VIEW user_with_address AS
SELECT u.id, u.email, a.city, a.country
FROM users u JOIN addresses a ON a.user_id = u.id;
CREATE TRIGGER user_addr_update
INSTEAD OF UPDATE ON user_with_address
FOR EACH ROW EXECUTE FUNCTION update_user_addr();Функция триггера INSTEAD OF
Функция определяет, в какие базовые таблицы выполнять запись:
CREATE FUNCTION update_user_addr() RETURNS TRIGGER AS $$
BEGIN
UPDATE users SET email = NEW.email WHERE id = NEW.id;
UPDATE addresses SET city = NEW.city, country = NEW.country WHERE user_id = NEW.id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;Когда INSTEAD OF лучше логики приложения
Если представление обновляют многие потребители, централизация логики обновления в триггере обеспечивает согласованность. Если обновления выполняет только одно приложение, оставьте логику в коде приложения.
SECURITY BARRIER
Не позволяйте планировщику проталкивать условия фильтрации в ненадёжных потребителей представления, чтобы предотвратить утечку информации через стоимость выполнения:
CREATE VIEW my_things AS
SELECT * FROM things WHERE owner_id = current_user_id()
WITH (security_barrier);Безопасность на уровне строк как альтернатива
Современный PostgreSQL также поддерживает безопасность на уровне строк (RLS) в базовых таблицах — часто это чище, чем создание защищённых представлений.
ALTER TABLE things ENABLE ROW LEVEL SECURITY;
CREATE POLICY owner_only ON things USING (owner_id = current_user_id());Рекурсивные представления
PostgreSQL поддерживает рекурсивные представления (иерархию, из которой можно выполнять SELECT):
CREATE RECURSIVE VIEW tree (id, parent_id, depth) AS
SELECT id, parent_id, 0 FROM nodes WHERE parent_id IS NULL
UNION ALL
SELECT n.id, n.parent_id, t.depth + 1
FROM nodes n JOIN tree t ON n.parent_id = t.id;Разрешения
Выдавайте разрешение на представление, а не на базовые таблицы:
GRANT SELECT, UPDATE ON active_users TO app_user;Замечание о производительности
Триггер INSTEAD OF срабатывает для каждой строки. Для массовых операций DML это медленно. Часто лучше, чтобы вызывающие стороны записывали данные непосредственно в базовые таблицы.
Итоги
Представления могут быть доступными для записи.
- Простые представления: обновляются автоматически
- Сложные представления: триггеры INSTEAD OF
- WITH CHECK OPTION обеспечивает видимость строк
- RLS часто предоставляет более чистую модель безопасности
Быстрая проверка
Вы определили представление, объединяющее две таблицы. Можно ли по умолчанию выполнить UPDATE через него?
Часто задаваемые вопросы
Урок «Обновляемые представления и триггеры INSTEAD OF» бесплатный?
Да — полный текст урока «Обновляемые представления и триггеры INSTEAD OF» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Academy, подпишись на CoddyKit PRO. Курс SQL Academy содержит 4 уроков всего.
Чему я научусь в уроке «Обновляемые представления и триггеры INSTEAD OF»?
Делайте представления непосредственно обновляемыми или используйте триггеры INSTEAD OF, когда представление агрегирует или объединяет данные Ты практикуешь SQL Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать SQL Academy?
Предыдущий опыт не требуется. SQL Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Обновляемые представления и триггеры INSTEAD OF»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке SQL Academy?
Да. Каждый урок SQL Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Обычные представления: логическое повторное использование
- Обновляемые представления и триггеры INSTEAD OF
- Материализованные представления и стратегии REFRESH
- Когда нужна предварительная агрегация