Olá! Seja bem-vindo!
Executar um update sem where é uma das situações mais desagradáveis que pode acontecer na área de tecnologia, então o assunto de hoje é extremamente relevante: Como EVITAR UPDATE sem WHERE.
Se você já fez o treinamento de “Transact-SQL” para desenvolvedores, disponível em meu site, aprendeu meus 3 segredos para garantir que essa situação desastrosa nunca ocorra com você, porém nem todos que trabalham com o banco que você cuida fizeram o treinamento.
Por essa razão, hoje veremos uma forma de você definitivamente evitar update sem where nos bancos que você administra.
Como EVITAR UPDATE sem WHERE
Para impedir que desavisados façam update sem where em nosso banco usaremos triggers e a propriedade contexto_info. Abaixo o script da aula de hoje para você testar e usar como base na sua implementação:
[sociallocker id=”5114″]
------------------------------------------------------------------------------- -- Como evitar UPDATE sem WHERE ------------------------------------------------------------------------------- -------------------------------------------------------- -- Requisitos para nosso teste -------------------------------------------------------- -- Banco de testes use master if db_id('curso') is not null drop database curso go create database curso go use curso go -- cria a tabela amigos if object_id('amigos') is not null drop table amigos create table amigos (id int primary key, nome varchar(100), email varchar(100), dt_nascimento date) insert into amigos values (1, 'Zézão', '[email protected]', '1990-01-02') insert into amigos values (2, 'Zezinho', '[email protected]', '1990-02-01') insert into amigos values (3, 'Abismail', '[email protected]', '1991-03-04') insert into amigos values (4, 'Lazarildo', '[email protected]', '1991-03-04') insert into amigos values (5, 'Febril', '[email protected]', '1992-03-04') insert into amigos values (6, 'Falsiane', '[email protected]', null) go -------------------------------------------------------- -- O que ocorre em geral :S -------------------------------------------------------- -- Consultar amigos select * from amigos -- Atualizar a data de aniversário do amigo... update amigos set dt_nascimento = '1980-02-01' -------------------------------------------------------- -- SOLUÇÃO 1: Trigger para impedir rowcount = count(*) -------------------------------------------------------- -- Trigger para impedir if object_id('tr_amigos_impede_sem_where') is not null drop trigger tr_amigos_impede_sem_where go create trigger tr_amigos_impede_sem_where on amigos for update, delete as begin declare @count int = @@rowcount if @count = (select sum(row_count) from sys.dm_db_partition_stats where object_id = object_id('amigos') and index_id in (0,1)) begin raiserror('ATENÇÃO: Não é permitido atualizar todos os registros de uma só vez. A transação foi cancelada.', 16, 1) rollback transaction end end go -- TR permite somente update "COM where": update amigos set dt_nascimento = '1980-02-01' where id = 6 update amigos set dt_nascimento = '1980-02-01' select * from amigos go -- Permitir update sem where temporário para ADMINS alter table amigos disable trigger all update amigos set dt_nascimento = '1980-02-01' alter table amigos enable trigger all go -------------------------------------------------------- -- SOLUÇÃO 2: Permitir sem where via codigo da TR -------------------------------------------------------- if object_id('tr_amigos_impede_sem_where') is not null drop trigger tr_amigos_impede_sem_where go create trigger tr_amigos_impede_sem_where on amigos WITH ENCRYPTION for update, delete as begin declare @count int = @@rowcount if context_info() = 0x1234567890 begin set context_info 0x -- reinicia o context_info para permitir apenas 1 execução sem where print 'Contexto admin, verificação de update/delete sem where não realizada.' end else if @count = (select sum(row_count) from sys.dm_db_partition_stats where object_id = object_id('amigos') and index_id in (0,1)) begin raiserror('ATENÇÃO: Não é permitido atualizar todos os registros de uma só vez. A transação foi cancelada.', 16, 1) rollback transaction end end -- TR é desativada no "context_info administrativo": select context_info from sys.dm_exec_sessions where session_id = @@spid; set context_info 0x1234567890; update amigos set dt_nascimento = '1980-02-01' where id = 6 update amigos set dt_nascimento = '1980-02-01' where id between 1 and 3 update amigos set dt_nascimento = '1980-02-01' select * from amigos go
[/sociallocker]
Se você quiser, pode inclusive melhorar essa trigger para que ela registre em um log as tentativas de update sem where. Se esse for o caso, consulte o meu artigo “Como descobrir quem mexeu no seu SQL” para entender melhor como você pode registrar informações em um log usando uma trigger. Somando o conhecimento de hoje com o do artigo que indiquei você terá a base necessária para fazer essa implementação com maestria.
CONCLUSÃO
Update sem where só é engraçado em memes da internet…
Brincadeiras a parte, espero muito que você que acompanha o blog e já fez meus treinamentos NUNCA passe por uma dessas. Alias, em poucas ocasiões podemos de verdade usar as palavras NUNCA e/ou SEMPRE, mas acho que para esse caso é apropriado:
– NUNCA deixe de usar as técnicas que lhe ensinei no curso evitar update sem where;
– SEMPRE preocupe-se em evitar que outros façam update sem where nos bancos que você cuida.
Espero que também tenha gostado desse conteúdo.
Abraço do seu amigo Josué 🙂