Curso
Apagar dados é uma operação que pode ser arriscada no SQL. Um único comando mal escrito pode bagunçar as relações entre tabelas ou até mesmo apagar um conjunto de dados inteiro.
Neste tutorial, vou mostrar como funciona a instrução ` DELETE `, como usá-la corretamente e como evitar erros comuns, como apagar um conjunto de dados inteiro, como acabei de mencionar.
Se você é novo no SQL, comece com nosso curso Introdução ao SQL ou, se já tem alguma experiência, vá direto para o curso SQL Intermediário.
O que o DELETE faz no SQL?
Antes de ver a sintaxe, é importante entender o que a instrução ` DELETE ` realmente faz. Aqui estão as diferentes maneiras de apagar dados no SQL.
SQL DELETE vs. remoção de linhas conceitualmente
A instrução ` DELETE ` remove uma ou mais linhas de uma tabela, mantendo a estrutura da tabela. Então, o esquema da tabela, que inclui os nomes das colunas, tipos de dados, índices e restrições, continua intacto. Depois de apagar, a tabela ainda tá lá e pronta pra receber novos dados.
Pense nisso como apagar entradas de um livro-razão, não como arrancar as páginas. O esquema continua o mesmo; só os registros selecionados são removidos.
SQL DELETE vs. DROP vs. TRUNCATE
Embora DELETE, DROP e TRUNCATE removam dados de alguma forma, elestêm finalidades bem diferentes. A tabela a seguir resume o uso de cada instrução:
|
Características |
EXCLUIR |
TRUNCATE |
DROP |
|
Tipo de comando |
DDL (Linguagem de Definição de Dados) |
||
|
Âmbito |
Remove linhas específicas (usando uma cláusul |
Remove todas as linhas de uma tabela |
Remove toda a tabela e seus dados. |
|
Velocidade |
Mais lento (remove linha por linha) |
Mais rápido (desaloca páginas) |
Instantâneo |
|
Reversibilidade |
Pode ser revertido |
Não reversível |
Não dá pra voltar atrás. |
|
Estrutura da tabela |
Conservado |
Preservado (e redefine IDs) |
Apagado completamente |
Sintaxe básica do comando DELETE do SQL
Agora que você já entendeu como funciona a instrução ` DELETE `, vamos ver sua sintaxe e como aplicá-la.
Apagando linhas específicas com WHERE
A cláusula ` WHERE ` define o escopo de uma operação ` DELETE `. A cláusula ` WHERE ` é sempre necessária, pois informa ao banco de dados exatamente quais linhas devem ser removidas.
-- Basic DELETE syntax
DELETE FROM table_name
WHERE condition;
Apagando todas as linhas de uma tabela
Se você deixar de fora a cláusula ` WHERE ` na instrução ` DELETE `, o SQL vai achar que você quer pegar todas as linhas da tabela. Se você fizer isso sem querer, o mecanismo do banco de dados vai passar por todos os registros e apagá-los. Para cada linha excluída, é feita uma entrada no log de transações. Se você tiver milhões de linhas, isso pode ser bem lento e fazer com que seus arquivos de log fiquem enormes.
Práticas seguras para SQL DELETE
Como uma operação do tipo “ DELETE ” pode ser permanente, implementar práticas seguras de exclusão vai te ajudar a desacelerar, verificar a intenção e planejar como recuperar se/quando algo der errado.
Visualizando linhas antes de excluir
Antes de executar uma instrução ` DELETE `, sempre visualize as linhas que você está prestes a remover usando uma instrução ` SELECT ` com a mesma condição ` WHERE ` que você planeja usar em sua instrução ` DELETE`. Se a instrução ` SELECT ` retornar muitas linhas ou linhas erradas, você pode corrigir a condição antes que algum dano seja causado.
Por exemplo, a consulta abaixo verifica se há linhas com pedidos cancelados antes de 2023-01-01 e, em seguida, usa os mesmos filtros para excluir esses registros.
-- Step 1: Preview the targets
SELECT * FROM Orders
WHERE Status = 'Cancelled' AND OrderDate < '2023-01-01';
-- Step 2: Once you've verified the list, convert to DELETE
DELETE FROM Orders
WHERE Status = 'Cancelled' AND OrderDate < '2023-01-01';
Usando transações e reversão
Se você colocar a operação ` DELETE ` dentro de uma transação, vai poder executar um comando, ver quantas linhas foram afetadas e, então, decidir se quer tornar a alteração permanente ou desfazê-la completamente. Você pode usar o ROLLBACK para restaurar os dados ao estado anterior.
A consulta abaixo exclui temporariamente as linhas qualificadas e, em seguida, as restaura, permitindo que você confirme o impacto sem perder dados.
BEGIN TRANSACTION;
DELETE FROM Users
WHERE LastLogin < '2020-01-01';
-- Inspect the affected row count
ROLLBACK;
Você pode usar a seguinte consulta para excluir permanentemente os usuários que fizeram login pela última vez antes de 1º de janeiro de 2020.
BEGIN TRANSACTION;
DELETE FROM Users
WHERE LastLogin < '2020-01-01';
-- Confirm deletion of the required rows
COMMIT;
Mas, é bom lembrar que o comando ` ROLLBACK ` só funciona se você ainda não tiver confirmado a transação.
SQL DELETE com junções e subconsultas
Nos bancos de dados do mundo real, os dados raramente existem isoladamente. Na maioria dos casos, você pode precisar excluir linhas com base em valores armazenados em outras tabelas, contas expiradas, registros órfãos ou entidades relacionadas que não se aplicam mais.
Apagando linhas com base em outra tabela
Usar subconsultas é a maneira mais portátil e amplamente suportada para excluir linhas com base em outra tabela. Eles funcionam em quase todas as versões do SQL. Por exemplo, a consulta abaixo exclui usuários inativos da tabela Users que desativaram contas da tabela Accounts.
-- Delete users whose accounts have been deactivated
DELETE FROM Users
WHERE AccountId IN (
SELECT AccountId
FROM Accounts
WHERE Status = 'DEACTIVATED'
);
Você também pode usar Joins para excluir linhas em um banco de dados, mas a sintaxe varia de acordo com o banco de dados, como veremos na próxima seção.
Sintaxe DELETE específica do banco de dados
Embora a ideia da instrução ` DELETE ` seja a mesma no SQL, diferentes bancos de dados têm sintaxes diferentes ao usar ` JOIN ` para excluir linhas de uma tabela com base em outra.
O SQL Server coloca a tabela de destino depois da instrução ` DELETE ` e, em seguida, faz a junção em ` FROM`. No exemplo abaixo, o alias após DELETE (u) mostra qual tabela está sendo apagada.
-- SQL Server: Delete users linked to deactivated accounts
DELETE u
FROM Users u
JOIN Accounts a
ON u.AccountId = a.AccountId
WHERE a.Status = 'DEACTIVATED';
No PostgreSQL, o objeto de controle de transação ( USING ) funciona como um objeto de controle de transação ( JOIN). Só as linhas da tabela de destino (Users) são excluídas.
-- PostgreSQL: Delete users linked to deactivated accounts
DELETE FROM Users
USING Accounts
WHERE Users.AccountId = Accounts.AccountId
AND Accounts.Status = 'DEACTIVATED';
O MySQL permite exclusões em várias tabelas, mas precisa que você diga o nome das tabelas. Você precisa colocar a tabela que vai ser excluída antes da cláusula ` FROM `.
-- MySQL: Delete users linked to deactivated accounts
DELETE u
FROM Users u
JOIN Accounts a
ON u.AccountId = a.AccountId
WHERE a.Status = 'DEACTIVATED';
Recomendo fazer nosso curso Joining Data in SQL para aprenderos diferentes tipos de junções em SQL e como trabalhar com diferentes tabelas relacionadas no banco de dados.
SQL DELETE e Integridade Referencial
Como a gente já sabe, as tabelas raramente ficam sozinhas em um banco de dados relacional. Eles geralmente são conectados usando chaves estrangeiras. Por causa dessas ligações, apagar uma linha em uma tabela pode trazer consequências indesejadas.
Chaves estrangeiras e erros de restrição
Quando uma tabela é referenciadapor uma chave estrangeira, o banco de dados aplica regras sobre o que acontece quando você tenta excluir uma linha pai. Por padrão, a maioria dos bancos de dados não deixa você apagar uma linha se ainda tiver outras relacionadas em uma tabela secundária.
Por exemplo, se você tiver uma tabela Orders que faz referência à tabela Customers, a exclusão de um cliente que ainda tenha pedidos falhará com um erro de restrição. Isso evita que o banco de dados tenha registros órfãos que não têm mais um pai válido.
Exclusões em cascata
Se você quiser excluir dados relacionados automaticamente, precisa definir explicitamente uma regra em cascata que instrua o banco de dados sobre como lidar com os dados relacionados. O evento " ON DELETE CASCADE " diz ao banco de dados para apagar automaticamente as linhas filhas relacionadas quando uma linha pai é removida.
Por exemplo, a consulta abaixo diz ao banco de dados para apagar automaticamente todas as linhas da tabela Orders que fazem referência a um cliente quando esse cliente é apagado da tabela Customers.
-- Parent table
CREATE TABLE Customers (
CustomerId INT PRIMARY KEY,
Name VARCHAR(100)
);
-- Child table with a cascading foreign key
CREATE TABLE Orders (
OrderId INT PRIMARY KEY,
CustomerId INT,
OrderDate DATE,
CONSTRAINT fk_orders_customers
FOREIGN KEY (CustomerId)
REFERENCES Customers(CustomerId)
ON DELETE CASCADE
);
A vantagem dessa abordagem é que ela mantém o banco de dados limpo sem precisar de várias instruções manuais ` DELETE `. Mas, é bom tomar cuidado com essa instrução, porque uma única exclusão pode causar uma reação em cadeia em várias tabelas, removendo muito mais dados do que o esperado. Por exemplo, você pode excluir uma linha em uma tabela Departments e, sem querer, acabar apagando 500 linhas em uma tabela Employees.
Considerações sobre desempenho ao excluir dados
Ao usar a instrução ` DELETE `, você vai perceber que excluir algumas linhas é instantâneo, mas lento se você tiver milhões de linhas. Pense nessas dicas para apagar registros com segurança:
DELETE vs. TRUNCATE para tabelas grandes
Como vimos antes, DELETE e TRUNCATE removem registros das seguintes maneiras:
-
DELETE: Ele percorre todas as linhas, verifica se elas atendem aos critérios, remove-as e registra a alteração no log de transações. Isso consome muitos recursos e é lento para conjuntos de dados enormes. Permite filtrar com uma cláusula `WHERE` e suporta reversão. -
TRUNCATE: Remove todas as linhas de uma veze com o mínimo de registro. É bem mais rápido, mas não dá pra filtrar, geralmente não dá pra reverter e é bloqueado por restrições de chave estrangeira.
Exclusões em lote e operações de longa duração
Se você excluir milhões de linhas em uma única instrução, isso pode deixar todo o seu aplicativo bem lento e até mesmo fazer com que seu banco de dados trave, se não for feito da maneira certa. Para diminuir esse risco, sempre apague conjuntos de dados grandes em lotes.
As exclusões em lote removem um número limitado de linhas de cada vez, como alguns milhares por operação. Isso faz com que o banco de dados continue ágil e fácil de acompanhar o progresso. Se algo der errado, você pode parar o processo sem precisar reverter uma transação enorme.
Erros comuns no SQL DELETE
Aqui estão os erros mais comuns que você deve evitar ao usar a instrução DELETE para remover linhas das suas tabelas:
Esquecendo a cláusula WHERE
Esquecer a cláusula ` WHERE ` é o erro mais comum ao usar ` DELETE`. Sem isso, a instrução remove todas as linhas da tabela. Sempre use a cláusula ` WHERE ` para especificar as linhas a serem excluídas. Como medida preventiva, use o hábito “ SELECT-before-DELETE ” que falamos antes para ver as linhas antes de apagar.
Supondo que DELETE seja reversível
Outro equívoco comum é achar que os dados apagados sempre podem ser recuperados. É bom saber que, por padrão, a instrução ` DELETE `, uma vez confirmada, marca os dados como fisicamente removidos do disco, a menos que você tenha backups, réplicas ou registros de auditoria em vigor.
Você só pode “desfazer” um comando “ DELETE ” se:
- É executado dentro de uma transação.
- A transação não foi confirmada.
- O banco de dados e o mecanismo de armazenamento suportam reversão.
SQL DELETE em ambientes de produção
Nos sistemas de produção, a operação “ DELETE ” tem mais a ver com controle, visibilidade e responsabilidade do que com sintaxe. Nesses ambientes, o objetivo não é só remover os dados, mas fazer isso de forma segura e cuidadosa.
Controle de acesso e permissões
Num ambiente profissional, a capacidade de apagar dados deve seguir o Princípio do Mínimo Privilégio. Nem todo usuário ou conta de serviço de aplicativo deve ter permissões d DELETE.
A maioria dos usuários com acesso "somente leitura" ou ferramentas de relatórios devem ter esse direito explicitamente negado. A maioria das empresas normalmente exige uma “Revisão por Pares”, em que uma segunda pessoa precisa verificar a cláusula WHERE de um script de exclusão manual antes que ele seja executado na produção.
Sevocê costuma projetar ou cuidar de bancos de dados no seu trabalho, recomendo que experimente o programa de habilidades do SQL Server para administradores de banco de dados.
Auditoria e exclusões temporárias
Muitos sistemas de produção evitam exclusões definitivas por causa dos riscos que isso traz. Em vez disso, eles usam exclusões temporárias, onde uma linha é marcada como excluída. Por exemplo, você pode usar um carimbo de data/hora ( deleted_at ) ou um sinalizador ( is_deleted ) em vez de remover fisicamente um registro.
As exclusões temporárias facilitam a recuperação, ajudam na auditoria e mantêm os dados históricos para fins de depuração e conformidade.
Conclusão
A lição mais importante é esta: Sempre defina uma cláusula WHERE clara, visualize as linhas afetadas com SELECT e use transações sempre que possível. Nos sistemas de produção, toda exclusão deve ser deliberada e auditável. Trate o DELETE com o mesmo cuidado que você daria a uma alteração de esquema ou a uma implantação, e ele continuará sendo uma ferramenta útil, em vez de um erro caro.
Recomendo fazer nossocurso de Design de Banco de Dados, onde você vai aprender a criar e gerenciar bancos de dados e escolher o DBMS certo para suas necessidades. Também recomendo experimentar nossoprograma de Engenheiro de Dados Associado em SQLpara aprender os fundamentos da engenharia de dados e do warehouse.
Obtenha uma das melhores certificações em SQL
Perguntas frequentes sobre SQL DELETE
Qual é a diferença entre DELETE, TRUNCATE e DROP?
DELETE remove as linhas selecionadas, TRUNCATE remove todas as linhas rapidinho e DROP apaga a própria tabela.
Por que a cláusula WHERE é importante no DELETE?
Sem a cláusula “ WHERE ”, “ DELETE ” remove todas as linhas, com o risco de perda total dos dados.
Por que algumas operações DELETE falham?
As restrições de chave estrangeira impedem a exclusão se existirem linhas filhas dependentes sem regras em cascata.
Como posso ver com segurança o que vai ser apagado?
Use uma instrução ` SELECT ` com a mesma condição ` WHERE ` para verificar as linhas afetadas antes de excluí-las.
Como posso excluir grandes conjuntos de dados com segurança?
Use exclusões em lote para remover linhas em blocos, evitando transações demoradas e problemas de desempenho.
