Um cliente excluído pelo sistema pode continuar aparecendo em uma consulta feita direto no banco, e um código de produto que o sistema diz não existir pode ser recusado como repetido em um cadastro novo. Os dois casos costumam ter a mesma origem. Muitos sistemas não removem a linha ao excluir um registro, apenas marcam a linha como excluída e deixam de mostrá-la. Esse modelo se chama exclusão lógica.
Marcar em vez de remover
Na exclusão física, o comando DELETE remove a linha da tabela. Na exclusão lógica, a aplicação grava uma marca na própria linha, com um UPDATE, e deixa de mostrar as linhas marcadas nas telas e nos relatórios. A linha continua na tabela, com todos os dados.
A marca pode ter formas diferentes:
- uma coluna de indicação, como
excluido, com a letra S nas linhas excluídas; - uma coluna de data, como
excluido_em, que fica em NULL enquanto o registro está ativo e recebe o momento da exclusão; - a própria situação do registro, quando o sistema trata a exclusão como uma inativação.
No cenário, as tabelas de cadastro, como clientes e produtos, têm a coluna excluido, do tipo CHAR(1). A aplicação grava a letra N nos cadastros novos e a letra S quando um cadastro é excluído. Na tabela produtos, essa marca não se confunde com a coluna ativo. Um produto inativo continua no cadastro e apenas deixa de ser vendido, enquanto um produto excluído deixa de aparecer nas telas.
Por que os sistemas marcam em vez de apagar
- Histórico: as vendas antigas continuam apontando para o cliente e para os produtos, e os relatórios do passado continuam completos.
- Reversão: um cadastro excluído por engano volta às telas com a retirada da marca. Essa reversão deve passar pela aplicação, quando ela oferece esse recurso, porque a exclusão pode ter sido acompanhada de outras alterações feitas pelo sistema.
- Sincronização: a marca é uma alteração da linha e pode ser enviada à matriz como qualquer outra alteração. Uma linha removida deixa de existir na loja, e em muitos mecanismos de sincronização não sobra nenhum vestígio da exclusão para ser enviado.
- Origem do sistema: nos antigos bancos de dados em arquivos, a exclusão marcava o registro, e uma rotina de manutenção removia depois os registros marcados. Os sistemas que nasceram nesses bancos costumam conservar esse comportamento.
A condição que esconde as linhas marcadas
Uma consulta feita direto no banco não conhece a regra da aplicação e mostra também as linhas marcadas. Para contar o mesmo conjunto que o sistema mostra, a consulta precisa repetir a condição da aplicação.
Quando a coluna da marca é criada em uma tabela que já tem dados, as linhas antigas podem ficar com a coluna em NULL. Como uma comparação com NULL nunca resulta em verdadeiro, as condições excluido = 'N' e excluido <> 'S' deixam essas linhas de fora. A condição (excluido IS NULL OR excluido <> 'S') considera os dois casos. Duas contagens ajudam na comparação com a tela:
SELECT COUNT(*) FROM clientes WHERE (excluido IS NULL OR excluido <> 'S');: conta os clientes não marcados como excluídos;SELECT COUNT(*) FROM clientes WHERE excluido = 'S';: conta os clientes marcados como excluídos.
Os parênteses mantêm as duas partes juntas quando a consulta tem outras condições, como um período ou uma situação. Mesmo com a marca considerada, a tela pode aplicar outros filtros, e a comparação entre uma contagem e a tela só vale quando os filtros são os mesmos.
A linha marcada continua ocupando os valores
A linha excluída logicamente conserva todos os valores, inclusive os que precisam ser únicos. Se a coluna codigo da tabela produtos tiver uma regra de valor único no banco, o cadastro de um produto novo com o código de um produto excluído é recusado com o erro 1062, de entrada duplicada, embora a busca do sistema não mostre nenhum produto com esse código. A consulta pelo código, sem a condição da marca, mostra a linha que ocupa o valor:
SELECT id, codigo, descricao, excluido FROM produtos WHERE codigo = '7891234567890';
A recusa também pode vir da própria aplicação. Se a rotina de cadastro procura o código em todas as linhas, inclusive nas marcadas, o sistema recusa o código repetido com uma mensagem própria.
A remoção definitiva
Três operações diferentes podem atingir um registro:
- Exclusão pelo sistema: grava a marca, e a linha continua na tabela.
- Limpeza pelo sistema: uma rotina de manutenção, quando existe, remove de vez as linhas marcadas.
- DELETE direto no banco: remove a linha sem passar pela marca nem pelas outras ações da aplicação. A exclusão não fica registrada pelo sistema e pode não chegar à matriz.
Depois da remoção, a recuperação de um registro depende de uma cópia de segurança. A remoção das linhas também não reduz de imediato o tamanho dos arquivos da tabela no disco, porque o espaço liberado continua reservado para novas linhas.
No suporte
Antes de concluir que um registro sumiu ou que uma busca perdeu dados, convém consultar a linha direto no banco, sem nenhum filtro, e conferir a marca de exclusão. Uma contagem feita no banco só pode ser comparada com a tela quando repete a condição da marca e os demais filtros da tela.
Para guardar
- Na exclusão lógica, a linha continua na tabela com uma marca, e a aplicação deixa de mostrá-la.
- Uma consulta feita direto no banco mostra também as linhas marcadas.
- A condição que esconde as linhas marcadas precisa considerar as linhas com a marca em NULL.
- A linha marcada continua ocupando os valores únicos.
- O DELETE direto remove a linha sem a marca e sem as demais ações da aplicação.
Uma contagem feita no banco mostra 1.000 clientes, e a tela do sistema mostra 980. O que verificar?
Se a consulta incluiu os clientes marcados como excluídos e se os demais filtros são iguais aos da tela. A consulta SELECT COUNT(*) FROM clientes WHERE excluido = 'S'; conta os marcados. A diferença de 20, sozinha, não prova que existem exatamente 20 clientes excluídos.
O cadastro de um produto novo foi recusado com o erro 1062, de entrada duplicada, mas a busca do sistema não encontra nenhum produto com esse código. Qual é a explicação provável?
Um produto excluído logicamente com o mesmo código. A linha continua na tabela, e a regra de valor único da coluna também vale para ela. A consulta pelo código, sem a condição da marca, mostra essa linha. A solução passa pela aplicação, como a reativação do produto antigo, e não pela remoção da linha, que pode estar ligada ao histórico de vendas.