SQL DROP TABLE
Às vezes uma tabela não serve mais: era um teste, uma cópia temporária, uma ideia que não deu certo. Para jogá-la fora inteira, com a estrutura e todas as linhas, existe o DROP TABLE ("solte", "largue a tabela"). É um dos comandos mais curtos do SQL e um dos mais perigosos: o banco não pergunta "tem certeza?" e não existe lixeira. Nesta aula você vai apagar tabelas da Loja Aurora (no editor, cada Rodar traz tudo de volta), ver por que o banco às vezes se recusa e aprender a se proteger.
- Como apagar uma tabela com
DROP TABLE, e a diferença para oDELETE. DROP TABLE IF EXISTS: apagar só se existir, sem erro.- Por que o SQLite recusa apagar uma tabela que outras referenciam, e a ordem certa de apagar.
- O que some junto (os índices) e o que fica quebrado (as views).
- Como se proteger: transação, cópia e backup.
- Os erros reais:
no such table,FOREIGN KEY constraint failed,use DROP VIEW…
A ideia: jogar fora a gaveta
Imagine o fichário da loja, com uma gaveta para cada assunto: clientes, produtos, pedidos. Há duas coisas bem diferentes que você pode fazer com uma gaveta:
| No fichário | No SQL | Depois |
|---|---|---|
| Tirar todas as fichas e deixar a gaveta vazia no lugar | DELETE FROM tabela; | A tabela existe, com as colunas, e tem 0 linhas. Dá para pôr fichas novas. |
| Arrancar a gaveta do móvel e jogar fora, com fichas e tudo | DROP TABLE tabela; | A tabela não existe mais. Para usar de novo, é preciso criá-la do zero. |
Esvaziar a tabela tem aula própria: Esvaziar uma Tabela. Esta aula é sobre jogar a gaveta fora.
1. O primeiro DROP TABLE
A Ana criou uma tabela de rascunho para testar os cupons, e agora não precisa mais dela:
CREATE TABLE rascunho (
id INTEGER PRIMARY KEY,
codigo TEXT
);
INSERT INTO rascunho (codigo) VALUES ('TESTE1'), ('TESTE2');
DROP TABLE rascunho;
- DROP TABLE
- "Jogue fora a tabela". Apaga a tabela inteira: as colunas, as regras e todas as linhas.
- rascunho
- O nome da tabela. Um só por comando, no SQLite.
O quadro diz só "DROP TABLE: ok". Não diz quantas linhas foram embora, nem pede confirmação. E se a Ana tentar usar a tabela depois?
CREATE TABLE rascunho (
id INTEGER PRIMARY KEY,
codigo TEXT
);
INSERT INTO rascunho (codigo) VALUES ('TESTE1'), ('TESTE2');
DROP TABLE rascunho;
SELECT * FROM rascunho;
no such table: rascunho, "não existe a tabela rascunho". Para o banco, é como se ela nunca tivesse existido.
No terminal
No banco da Ana, no computador dela, o efeito aparece no .tables. Repare que o DROP TABLE não mostra nada quando dá certo:
$ sqlite3 loja.db SQLite version 3.50.4 2025-07-30 19:33:53 Enter ".help" for usage hints. sqlite> .tables categorias fornecedores itens_pedido produtos clientes funcionarios pedidos sqlite> DROP TABLE itens_pedido; sqlite> .tables categorias fornecedores pedidos clientes funcionarios produtos sqlite> SELECT COUNT(*) FROM itens_pedido; Parse error: no such table: itens_pedido sqlite> .quit
Os 220 itens de pedido foram embora. Ao contrário do editor, aqui é o arquivo loja.db de verdade: não volta mais. (Para a Ana, a sorte é que esse banco é uma cópia de estudo.)
2. DROP TABLE IF EXISTS
Apagar uma tabela que não existe é erro:
DROP TABLE cupons;
Num roteiro que recria as tabelas do zero, esse erro atrapalha: na primeira vez, a tabela ainda não existe, e o roteiro para no primeiro comando. Para isso há o IF EXISTS ("se existir"):
DROP TABLE IF EXISTS cupons;
CREATE TABLE cupons (
id INTEGER PRIMARY KEY,
codigo TEXT NOT NULL,
desconto REAL NOT NULL
);
INSERT INTO cupons (codigo, desconto) VALUES ('NATAL', 15);
SELECT * FROM cupons;
- IF EXISTS
- "Se existir": se a tabela existe, apaga; se não existe, não faz nada e não dá erro. O roteiro segue em frente.
Esse roteiro pode rodar quantas vezes você quiser: cada vez, ele joga fora a tabela velha (se houver) e cria uma nova, limpinha. É exatamente o que faz o arquivo que monta a Loja Aurora (o aurora.sql): ele começa com sete linhas DROP TABLE IF EXISTS, uma por tabela, antes dos CREATE TABLE.
O contrário também existe: CREATE TABLE IF NOT EXISTS cupons (…) cria a tabela só se ela ainda não existir (aula CREATE TABLE). Sem ele, criar uma tabela que já existe dá table cupons already exists.
3. Quando o banco se recusa: as chaves estrangeiras
A Ana tenta apagar a tabela de pedidos:
DROP TABLE pedidos;
FOREIGN KEY constraint failed. A tabela itens_pedido tem uma chave estrangeira apontando para pedidos (aula FOREIGN KEY). Com a regra ligada, como no editor, o DROP TABLE primeiro apaga todas as linhas da tabela, e isso deixaria 220 itens apontando para pedidos que não existem. O banco recusa, e a tabela pedidos continua inteira. O IF EXISTS não ajuda aqui: DROP TABLE IF EXISTS pedidos; dá o mesmo erro, porque a tabela existe.
A ordem certa: dos filhos para as mães
Para apagar várias tabelas ligadas, comece pela que ninguém referencia e vá subindo:
DROP TABLE itens_pedido; -- ninguém aponta para os itens DROP TABLE pedidos; -- agora ninguém aponta para os pedidos DROP TABLE clientes; -- nem para os clientes SELECT name FROM sqlite_schema WHERE type = 'table';
Sobraram quatro tabelas. Na Loja Aurora, as setas das chaves estrangeiras são estas (a filha à esquerda, as mães à direita):
itens_pedido → pedidos, produtos pedidos → clientes, funcionarios produtos → categorias, fornecedores funcionarios → funcionarios (o chefe)
Para apagar tudo, comece por quem está só à esquerda (itens_pedido) e termine pelas que só aparecem à direita (clientes, categorias, fornecedores).
Experimente: o código tenta apagar pedidos e depois itens_pedido, e para no primeiro comando com FOREIGN KEY constraint failed. Troque a ordem dos dois DROP TABLE. O SELECT do fim vai dar erro, e esse erro é a prova de que deu certo: no such table: pedidos.
DROP TABLE pedidos; DROP TABLE itens_pedido; SELECT COUNT(*) FROM pedidos;
DROP TABLE itens_pedido; DROP TABLE pedidos; SELECT COUNT(*) FROM pedidos;
No terminal, a regra vem desligada
Lembra que, no programa sqlite3, as chaves estrangeiras vêm desligadas (aula FOREIGN KEY)? Então lá o DROP TABLE de uma tabela mãe passa sem reclamar, e deixa os filhos órfãos:
$ sqlite3 loja.db SQLite version 3.50.4 2025-07-30 19:33:53 Enter ".help" for usage hints. sqlite> DROP TABLE clientes; sqlite> SELECT COUNT(*) FROM pedidos; 90 sqlite> SELECT COUNT(*) FROM clientes; Parse error: no such table: clientes sqlite> .quit
Os 90 pedidos continuam lá, apontando para clientes que não existem mais. Mais um motivo para começar toda sessão com PRAGMA foreign_keys = ON;.
4. O que vai junto e o que fica quebrado
Os índices vão junto
Um índice (aula Índices) pertence a uma tabela. Quando a tabela vai embora, os índices dela também:
CREATE INDEX idx_quantidade ON itens_pedido (quantidade); DROP TABLE itens_pedido; SELECT name, type FROM sqlite_schema WHERE name = 'idx_quantidade';
Nenhuma linha: o índice sumiu junto. O mesmo vale para os gatilhos (triggers) da tabela.
As views ficam quebradas
Uma view (aula Views) é uma consulta salva com nome. Ela não pertence a uma tabela; ela só usa a tabela. Por isso o SQLite não a apaga junto, e ela fica quebrada:
CREATE VIEW v_itens AS SELECT pedido_id, quantidade FROM itens_pedido; DROP TABLE itens_pedido; SELECT * FROM v_itens;
O DROP TABLE funcionou sem aviso; o erro só apareceu ao usar a view: no such table: main.itens_pedido (main é o nome do banco aberto). Antes de apagar uma tabela, confira quem a usa: SELECT name, type FROM sqlite_schema WHERE sql LIKE '%itens_pedido%';.
5. Como se proteger
Não existe "desfazer" para um DROP TABLE confirmado. Mas existem três redes de segurança, da mais rápida para a mais completa:
Dentro de uma transação
Entre um BEGIN e um COMMIT, nada é definitivo (aula Transações). Se você se arrepender antes do COMMIT, o ROLLBACK ("volte atrás") desfaz tudo, inclusive o DROP TABLE:
BEGIN; DROP TABLE itens_pedido; ROLLBACK; SELECT COUNT(*) AS itens FROM itens_pedido;
Os 220 itens estão de volta. No SQLite, até os comandos que mudam a estrutura (CREATE, ALTER, DROP) respeitam a transação; em alguns outros bancos, não (veja a nota no fim).
Uma cópia antes
Se a tabela pode fazer falta, guarde uma cópia numa tabela nova antes de apagar: CREATE TABLE itens_pedido_copia AS SELECT * FROM itens_pedido; (aula Criar Tabela a partir de Consulta).
Um backup do arquivo
A proteção completa é uma cópia do banco inteiro, feita antes de qualquer mudança grande. No SQLite, o banco é um arquivo, e o sqlite3 tem comandos próprios para isso (aula Backup).
| Rede de segurança | Protege contra | Quando usar |
|---|---|---|
BEGIN … ROLLBACK | Arrependimento dentro da mesma sessão, antes do COMMIT | Roteiros com vários passos, como a recriação de tabela da aula ALTER TABLE |
CREATE TABLE … AS SELECT | Precisar dos dados de uma tabela depois | Antes de apagar uma tabela que você "acha" que não serve mais |
| Backup do arquivo | Qualquer coisa, inclusive o que você não previu | Sempre, antes de mexer num banco que tem dados de verdade |
6. DROP TABLE, DELETE ou DROP COLUMN?
| Você quer | Use | O que sobra |
|---|---|---|
| Jogar fora a tabela inteira | DROP TABLE t; | Nada. |
| Apagar algumas linhas | DELETE FROM t WHERE …; (aula DELETE) | A tabela e as outras linhas. |
| Apagar todas as linhas, mantendo a tabela | DELETE FROM t; (aula Esvaziar uma Tabela) | A tabela vazia, com as colunas e regras. |
| Tirar uma coluna | ALTER TABLE t DROP COLUMN c; (aula ALTER TABLE) | A tabela, sem aquela coluna. |
| Apagar uma view | DROP VIEW v; | As tabelas que ela usava. |
| Apagar um índice | DROP INDEX i; | A tabela e os dados. |
Quando dá errado
A tabela não existe, ou o nome está errado, ou ela já foi apagada (por exemplo, rodando o mesmo roteiro duas vezes). Veja o exemplo da seção 2.
Como consertar: confira o nome com SELECT name FROM sqlite_schema WHERE type = 'table'; (ou .tables, no terminal). Se o roteiro precisa rodar várias vezes, use DROP TABLE IF EXISTS.
Outra tabela aponta para esta (seção 3).
Como consertar: apague antes as tabelas filhas (as que têm REFERENCES para esta). Para ver quem aponta para quem, use PRAGMA foreign_key_list(itens_pedido); em cada tabela.
DROP TABLE itens_pedido, pedidos;
A mensagem: near ",": syntax error. O SQLite apaga uma tabela por comando. (O MySQL e o PostgreSQL aceitam a lista; veja a nota abaixo.)
Como consertar: um DROP TABLE para cada tabela, na ordem certa.
CREATE VIEW clientes_pi AS SELECT nome FROM clientes WHERE estado = 'PI'; DROP TABLE clientes_pi;
A mensagem: use DROP VIEW to delete view clientes_pi, "use DROP VIEW para apagar a view clientes_pi". O SQLite até ensina o comando certo.
DROP TABLE sqlite_schema;
A mensagem: table sqlite_master may not be dropped, "a tabela sqlite_master não pode ser apagada". sqlite_schema e sqlite_master são dois nomes para a mesma tabela interna, a que guarda a descrição de todas as outras. Sem ela, o banco não saberia o que tem dentro.
DROP TABLES rascunho;
A mensagem: near "TABLES": syntax error. É sempre TABLE, no singular, mesmo que a tabela tenha um nome no plural.
DROP TABLE e DROP TABLE IF EXISTS existem no MySQL, no PostgreSQL e no SQL Server (neste, o IF EXISTS chegou na versão 2016). Algumas diferenças (trechos ilustrativos, não rodam no SQLite):
-- MySQL e PostgreSQL: várias tabelas num comando DROP TABLE IF EXISTS itens_pedido, pedidos; -- PostgreSQL: CASCADE apaga junto o que depende da tabela -- (views e as chaves estrangeiras de outras tabelas, não as outras tabelas) DROP TABLE pedidos CASCADE;
E um cuidado importante: no MySQL, um DROP TABLE confirma sozinho a transação aberta; um ROLLBACK depois dele não traz a tabela de volta. No PostgreSQL e no SQL Server, assim como no SQLite, o DROP TABLE dentro de uma transação pode ser desfeito.
Referência rápida
| Escrita | O que faz |
|---|---|
DROP TABLE t; | Apaga a tabela inteira: estrutura, regras, linhas, índices e gatilhos. |
DROP TABLE IF EXISTS t; | Apaga se existir; se não existir, não faz nada e não dá erro. |
BEGIN; DROP TABLE t; ROLLBACK; | Desfaz o DROP antes de confirmar. |
DROP VIEW v; / DROP INDEX i; | Apagam uma view ou um índice. |
| Ordem com chaves estrangeiras | Primeiro as filhas, depois as mães: itens_pedido → pedidos → clientes. |
| Mensagem | Quer dizer |
|---|---|
no such table: cupons | A tabela não existe (use IF EXISTS se isso for normal). |
FOREIGN KEY constraint failed | Outra tabela aponta para esta: apague a filha antes. |
near ",": syntax error | O SQLite não aceita lista de tabelas no DROP TABLE. |
use DROP VIEW to delete view clientes_pi | É uma view: use DROP VIEW. |
table sqlite_master may not be dropped | A tabela interna do SQLite não pode ser apagada. |
no such table: main.itens_pedido (ao usar uma view) | A view usa uma tabela que foi apagada. |
Exercícios
1. Sem erro se não existir
Complete para apagar a tabela rascunho só se ela existir:
2. A view
Complete o comando que apaga a view clientes_pi:
3. Qual é a diferença entre DELETE FROM cupons; e DROP TABLE cupons;?
4. No editor do guia, DROP TABLE clientes; dá FOREIGN KEY constraint failed. Por quê?
5. A Ana rodou BEGIN; DROP TABLE itens_pedido; ROLLBACK;. Quantos itens existem depois?
6. Existe uma view v_itens que usa itens_pedido. O que acontece com ela depois de DROP TABLE itens_pedido;?
Missão final: um roteiro que roda sempre
Missão: este roteiro deveria recriar a tabela de cupons do zero, mas para logo no primeiro comando, porque a tabela ainda não existe. Conserte só a primeira linha para que o roteiro funcione sempre: exista a tabela ou não.
DROP TABLE cupons;
CREATE TABLE cupons (
id INTEGER PRIMARY KEY,
codigo TEXT NOT NULL,
desconto REAL NOT NULL
);
INSERT INTO cupons (codigo, desconto) VALUES ('NATAL', 15);
SELECT codigo, desconto FROM cupons;
DROP TABLE IF EXISTS cupons;
CREATE TABLE cupons (
id INTEGER PRIMARY KEY,
codigo TEXT NOT NULL,
desconto REAL NOT NULL
);
INSERT INTO cupons (codigo, desconto) VALUES ('NATAL', 15);
SELECT codigo, desconto FROM cupons;
Resumo
DROP TABLE t;joga fora a tabela inteira: estrutura, regras, linhas, índices e gatilhos. Não pede confirmação e não tem lixeira.DROP TABLE IF EXISTS t;não dá erro se a tabela não existir: ideal para roteiros que recriam tabelas.- Com as chaves estrangeiras ligadas, apagar uma tabela que outras referenciam dá
FOREIGN KEY constraint failed: apague das filhas para as mães. No terminal, com a regra desligada, oDROPpassa e deixa órfãos. - Views que usavam a tabela não somem: ficam quebradas, com
no such table: main.…. - Proteja-se com transação (
BEGIN…ROLLBACK), cópia (CREATE TABLE … AS SELECT) e backup. - Para esvaziar sem jogar fora, use
DELETE FROM t;(próxima aula).