PostgreSQL CREATE TRIGGER
Os gatilhos no PostgreSQL são funções de retorno de chamada do banco de dados que são executadas ou disparadas automaticamente quando ocorre um evento específico do banco de dados, como uma operação `INSERT`, `UPDATE`, `DELETE` ou até mesmo `TRUNCATE`. Eles são usados para aplicar regras comerciais, validar dados e manter a integridade dos dados no banco de dados.
Uso
Os acionadores são usados para automatizar tarefas que devem ocorrer quando ocorrem eventos específicos no banco de dados, reduzindo a necessidade de intervenção manual ou de lógica no lado do aplicativo. Eles são definidos usando a instrução `CREATE TRIGGER`, especificando o evento e a ação a ser executada.
sql
CREATE TRIGGER trigger_name
{ BEFORE | AFTER | INSTEAD OF }
{ INSERT | UPDATE | DELETE | TRUNCATE }
ON table_name
[ FOR EACH ROW | FOR EACH STATEMENT ]
EXECUTE PROCEDURE function_name();
Nessa sintaxe, `CREATE TRIGGER` define um novo acionador chamado `trigger_name` que executa uma função especificada (`function_name`) antes, depois ou no lugar do evento especificado na `table_name`. A cláusula `FOR EACH ROW` indica que o acionador é executado uma vez para cada linha afetada pelo evento, enquanto a cláusula `FOR EACH STATEMENT` é executada uma vez por comando acionador, independentemente do número de linhas afetadas.
Exemplos
1. Gatilho de inserção básico
sql
CREATE FUNCTION log_insert() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (table_name, operation) VALUES ('employees', 'INSERT');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER log_employee_inserts
AFTER INSERT ON employees
FOR EACH ROW EXECUTE PROCEDURE log_insert();
Este exemplo cria um gatilho que registra cada operação de inserção na tabela `employees` em uma tabela `audit_log`.
2. Atualizar gatilho com condição
sql
CREATE FUNCTION check_salary_update() RETURNS TRIGGER AS $$
BEGIN
IF NEW.salary < OLD.salary THEN
RAISE EXCEPTION 'Salary cannot be decreased';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER prevent_salary_decrease
BEFORE UPDATE ON employees
FOR EACH ROW EXECUTE PROCEDURE check_salary_update();
Esse acionador impede qualquer redução no salário dos funcionários, garantindo que as atualizações salariais só possam aumentar ou permanecer iguais. Aqui, `NEW` e `OLD` representam os estados novo e antigo da linha que está sendo operada, respectivamente.
3. Acionador para exclusão em cascata
sql
CREATE FUNCTION delete_related_records() RETURNS TRIGGER AS $$
BEGIN
DELETE FROM orders WHERE customer_id = OLD.customer_id;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER cascade_delete_orders
AFTER DELETE ON customers
FOR EACH ROW EXECUTE PROCEDURE delete_related_records();
Este exemplo configura um acionador para excluir automaticamente todos os pedidos associados a um cliente quando esse cliente for excluído.
4. Exemplo de acionador INSTEAD OF
Os acionadores INSTEAD OF são normalmente usados com exibições para executar ações em vez da operação padrão.
sql
CREATE FUNCTION log_view_update() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (table_name, operation) VALUES ('view_name', 'UPDATE');
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER log_view_updates
INSTEAD OF UPDATE ON my_view
FOR EACH ROW EXECUTE PROCEDURE log_view_update();
Esse acionador registra tentativas de atualizar uma exibição em vez de executar a atualização.
Dicas e práticas recomendadas
- Defina claramente as condições de acionamento. Certifique-se de que as condições sob as quais os acionadores são disparados estejam bem definidas para evitar comportamentos inesperados.
- Use os gatilhos com moderação. O uso excessivo de acionadores pode levar a interdependências complexas e dificultar a depuração.
- Documente os acionadores minuciosamente. Forneça uma documentação clara sobre o que cada acionador faz e por que ele é usado para referência futura.
- Faça um teste completo. Sempre teste os acionadores em um ambiente de desenvolvimento para garantir que eles funcionem como pretendido, sem degradação do desempenho.
- Considere as implicações de desempenho. Os acionadores complexos podem afetar o desempenho; monitore-os e otimize-os quando necessário.
- Impedir a invocação recursiva. Use comandos como `ALTER TABLE ... ENABLE TRIGGER ...` para controlar a ativação do acionador e evitar possíveis loops de invocação recursiva.