CodeGym /Cursos /SQL SELF /Triggers em nível de linha e tabela: FOR EACH ROW vs FOR ...

Triggers em nível de linha e tabela: FOR EACH ROW vs FOR EACH STATEMENT

SQL SELF
Nível 58 , Lição 2
Disponível

Se você já passou por aquela situação em que precisa executar uma ação pra cada linha durante um update em massa, ou só uma vez pra tabela toda, provavelmente ficou na dúvida: como fazer isso do jeito certo? O PostgreSQL te dá duas opções: triggers em nível de linha e triggers em nível de statement. Entender quando usar cada uma é importante pra modelar bem o banco, otimizar a performance e evitar dor de cabeça. Bora entender como funciona!

Triggers que rodam em nível de linha (FOR EACH ROW) são disparadas toda vez pra cada linha afetada por um INSERT, UPDATE ou DELETE. Ou seja, se o SQL mexer em 100 linhas, o trigger vai rodar 100 vezes.

Quando usar?

Triggers em nível de linha são úteis quando você precisa tratar cada linha alterada separadamente. Por exemplo:

  • Logar mudanças de cada linha.
  • Atualizar dados relacionados automaticamente pra cada linha.

Exemplo: logando mudanças de cada linha

Imagina que temos uma tabela de estudantes:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    age INT,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Queremos logar cada linha que for atualizada nessa tabela em uma tabela separada chamada students_log:

CREATE TABLE students_log (
    log_id SERIAL PRIMARY KEY,
    student_id INT,
    old_name VARCHAR(100),
    new_name VARCHAR(100),
    changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Função pra logar as mudanças:

CREATE OR REPLACE FUNCTION log_student_update()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO students_log(student_id, old_name, new_name, changed_at)
    VALUES (OLD.id, OLD.name, NEW.name, CURRENT_TIMESTAMP);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Criando o trigger FOR EACH ROW:

CREATE TRIGGER student_update_logger
AFTER UPDATE ON students
FOR EACH ROW
EXECUTE FUNCTION log_student_update();

Testando:

UPDATE students
SET name = 'Ivan Ivanov'
WHERE id = 1;

Depois desse comando, vai aparecer um registro na tabela students_log com os detalhes da mudança.

Triggers em nível de statement (FOR EACH STATEMENT)

Triggers em nível de statement (FOR EACH STATEMENT) são disparadas uma vez só pra todo o comando SQL, não importa quantas linhas foram afetadas. Se o update mexer em 100 linhas, o trigger roda só uma vez.

Triggers em nível de statement são boas quando você precisa:

  • Executar uma ação só uma vez pra toda a operação.
  • Trabalhar com dados agregados ou fazer cálculos pra tabela inteira.

Exemplo: atualizando um contador de mudanças

Vamos supor que temos uma tabela de contador de mudanças pra tabela students:

CREATE TABLE students_changes_log (
    total_changes INT DEFAULT 0
);
INSERT INTO students_changes_log(total_changes) VALUES (0);

Queremos aumentar esse contador toda vez que rolar um UPDATE na tabela students.

Função pra atualizar o contador:

CREATE OR REPLACE FUNCTION increment_changes_counter()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE students_changes_log
    SET total_changes = total_changes + 1;
    RETURN NULL; -- Trigger em nível de statement não retorna linhas
END;
$$ LANGUAGE plpgsql;

Criando o trigger FOR EACH STATEMENT:

CREATE TRIGGER update_changes_counter
AFTER UPDATE ON students
FOR EACH STATEMENT
EXECUTE FUNCTION increment_changes_counter();

Testando:

UPDATE students
SET age = age + 1
WHERE age < 20;

Depois desse comando, o trigger vai rodar uma vez só e o contador de mudanças vai aumentar em um.

Comparando FOR EACH ROW e FOR EACH STATEMENT

Critério FOR EACH ROW FOR EACH STATEMENT
Nível de execução Pra cada linha afetada Uma vez pra toda a operação
Frequência de chamada Uma chamada por linha Uma chamada por comando SQL
Tarefas Log de mudanças individuais, processamento de linhas Agregação, atualização de metadados
Exemplo Logando mudanças de cada linha Atualizando contador de mudanças
Performance Mais pesado em operações em massa Mais leve pra operações em massa

Quando usar FOR EACH ROW e FOR EACH STATEMENT?

Use FOR EACH ROW se:

  1. Você quer que o trigger rode pra cada linha.
  2. A lógica precisa estar ligada à mudança de linhas específicas.
  3. Você precisa acessar os dados OLD e NEW de cada linha.

Exemplo: Log de mudanças na tabela ou criação automática de registros relacionados.

Use FOR EACH STATEMENT se:

  1. Você quer executar uma ação só uma vez pra toda a operação.
  2. A lógica do trigger não depende de mudanças em linhas específicas.
  3. Performance é crítica e não dá pra chamar o trigger várias vezes.

Exemplo: Atualizar contadores, calcular metadados da tabela.

Erros e pontos importantes

Usar o tipo certo de trigger pode não ser tão óbvio, então fica ligado:

  1. Um erro comum é tentar usar OLD e NEW num trigger FOR EACH STATEMENT. Isso vai dar erro, porque essas variáveis só existem em triggers de linha.
  2. Triggers de linha (FOR EACH ROW) podem deixar as operações bem lentas se o comando mexer em muitas linhas. Sempre pensa na performance.
  3. Cuidado com recursão de triggers. Por exemplo, se o trigger altera dados na mesma tabela, pode acabar num loop infinito.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION