Gatilhos (Triggers) em SQL: escopo de execução e efeito acumulado
Gabarito: letra E. O gatilho T1, definido como BEFORE DELETE sem a cláusula FOR EACH ROW, é um gatilho de nível de instrução e dispara uma única vez por comando DELETE, independentemente do número de linhas afetadas. Já o gatilho T2, definido como AFTER DELETE ... FOR EACH ROW, é um gatilho de nível de linha e dispara uma vez para cada linha removida. Como o comando I remove 2 linhas, o comando II remove 2 linhas e o comando III remove 0 linhas, o total de disparos de T1 é 3 (um por comando) e o de T2 é 4 (2+2+0). Assim, b1 = 0 + 3 = 3 e c1 = 0 + 4 = 4.
A questão exige compreender a diferença fundamental entre gatilhos de nível de instrução e de nível de linha. Um gatilho de nível de instrução (BEFORE DELETE ou AFTER DELETE sem FOR EACH ROW) executa seu corpo uma única vez para a instrução SQL inteira, não importando quantas tuplas são afetadas. Já um gatilho de nível de linha (FOR EACH ROW) executa o corpo uma vez para cada tupla afetada pela instrução. Essa distinção é crucial para prever o efeito acumulado de comandos de modificação em massa.
Vamos analisar o estado inicial das tabelas e o efeito de cada comando DELETE:
Tabela A: contém as tuplas (1,10), (2,10), (3,2) e (4,3).
Tabela B: contém a tupla (10,0), então b1 = 0.
Tabela C: contém a tupla (100,0), então c1 = 0.
Comando I: DELETE FROM A WHERE a1>=10; — Remove as tuplas com a1 maior ou igual a 10. Na tabela A, as tuplas (1,10) e (2,10) atendem à condição. Portanto, 2 linhas são removidas. O gatilho T1 (nível de instrução) dispara 1 vez, incrementando b1 para 1. O gatilho T2 (nível de linha) dispara 2 vezes (uma para cada linha removida), incrementando c1 para 2.
Comando II: DELETE FROM A WHERE a1<10; — Remove as tuplas com a1 menor que 10. As tuplas (3,2) e (4,3) atendem à condição. Portanto, 2 linhas são removidas. O gatilho T1 dispara 1 vez, incrementando b1 para 2. O gatilho T2 dispara 2 vezes, incrementando c1 para 4.
Comando III: DELETE FROM A WHERE a1 is null; — Remove as tuplas onde a1 é NULL. Como nenhuma tupla na tabela A tem a1 NULL, 0 linhas são removidas. O gatilho T1 dispara 1 vez (mesmo sem linhas afetadas, o comando é executado), incrementando b1 para 3. O gatilho T2 dispara 0 vezes, pois não há linhas para iterar, mantendo c1 em 4.
A pegadinha central está em dois pontos: (1) o gatilho de nível de instrução T1 dispara mesmo quando o DELETE não remove nenhuma linha, pois ele é executado antes da operação, independentemente do resultado; (2) o gatilho de nível de linha T2 só dispara para linhas efetivamente removidas. Muitos candidatos erram ao contar o número de disparos de T1 como se fosse por linha, ou ao ignorar o disparo de T1 no comando III.
Guarde a distinção entre nível de instrução (uma vez por comando) e nível de linha (uma vez por tupla afetada) — é exatamente nela que as alternativas se dividem.
Alternativa A — ❌ Incorreta
Afirma que b1 = 2 e c1 = 2. O valor de b1 está incorreto, pois o gatilho T1 dispara 3 vezes (uma por comando DELETE), resultando em b1 = 3. O valor de c1 também está incorreto, pois o gatilho T2 dispara 4 vezes (2+2+0), resultando em c1 = 4. A alternativa subestima ambos os contadores, provavelmente por considerar apenas os comandos I e II, ignorando o disparo de T1 no comando III e contando T2 apenas para as linhas efetivamente removidas nos dois primeiros comandos.
Alternativa B — ❌ Incorreta
Afirma que b1 = 2 e c1 = 3. O valor de b1 está incorreto (deveria ser 3, pois T1 dispara 3 vezes). O valor de c1 também está incorreto (deveria ser 4, pois T2 dispara 4 vezes). A alternativa parece contar T1 apenas para os comandos I e II (ignorando o comando III) e T2 como 2+1, o que não corresponde a nenhuma lógica de disparo correta.
Alternativa C — ❌ Incorreta
Afirma que b1 = 2 e c1 = 4. O valor de b1 está incorreto (deveria ser 3). O valor de c1 está correto (4). A alternativa acerta o valor de c1, mas erra o de b1, provavelmente por ignorar o disparo de T1 no comando III, que não remove nenhuma linha, mas ainda assim executa o gatilho de nível de instrução.
Alternativa D — ❌ Incorreta
Afirma que b1 = 3 e c1 = 2. O valor de b1 está correto (3). O valor de c1 está incorreto (deveria ser 4). A alternativa acerta o valor de b1, mas erra o de c1, provavelmente por contar T2 apenas para o comando I (2 disparos) e ignorar os disparos do comando II, ou por considerar que T2 dispara apenas uma vez por comando, o que é incorreto para um gatilho de nível de linha.
Alternativa E — ✅ Correta ⟵ GABARITO
Afirma que b1 = 3 e c1 = 4. O valor de b1 = 3 está correto, pois o gatilho T1, de nível de instrução, dispara uma vez para cada comando DELETE (I, II e III), totalizando 3 incrementos. O valor de c1 = 4 está correto, pois o gatilho T2, de nível de linha, dispara uma vez para cada linha removida: 2 linhas no comando I + 2 linhas no comando II + 0 linhas no comando III = 4 disparos. A alternativa reflete corretamente a diferença entre os dois tipos de gatilho.
A regra de ouro para questões de gatilhos é identificar o escopo: FOR EACH ROW significa que o gatilho executa para cada linha afetada, enquanto sua ausência significa que ele executa uma única vez por instrução. No comando III, mesmo sem linhas removidas, o gatilho de nível de instrução T1 ainda é executado, pois ele é disparado antes da operação de exclusão, independentemente do resultado.
Gabarito: letra E