🧚 Ei! O Beekeeper Studio é uma GUI de banco de dados rápida, moderna e open source Download
7 de janeiro de 2026 Por Matthew Rathbone

Remover duplicatas em SQL significa uma de duas coisas: ocultar linhas repetidas do resultado de uma consulta com DISTINCT, ou excluir as cópias extras da tabela para que reste apenas uma de cada. Os exemplos funcionam em PostgreSQL, MySQL, SQLite e SQL Server.

Como remover duplicatas em SQL

SELECT DISTINCT retorna cada combinação das colunas listadas uma única vez e não altera a tabela. Para limpar a própria tabela, exclua todas as linhas exceto uma em cada grupo de duplicatas, geralmente a de menor id:

SELECT DISTINCT column_list FROM table_name;

DELETE FROM table_name
WHERE id NOT IN (
  SELECT id FROM (
    SELECT MIN(id) AS id FROM table_name GROUP BY column_list
  ) AS keepers
);

Aqui, Maria Lopez foi cadastrada três vezes:

-- Input: customers
-- id | name        | email             | phone
-- ---+-------------+-------------------+---------
-- 1  | Maria Lopez | maria@example.com | 555-0142
-- 2  | Sam Patel   | sam@example.com   | 555-0178
-- 3  | Maria Lopez | maria@example.com | 555-0142
-- 4  | Lena Novak  | lena@example.com  | 555-0121
-- 5  | Maria Lopez | maria@example.com | 555-0142

SELECT DISTINCT name, email, phone
FROM customers
ORDER BY name;

-- Output:
-- name        | email             | phone
-- ------------+-------------------+---------
-- Lena Novak  | lena@example.com  | 555-0121
-- Maria Lopez | maria@example.com | 555-0142
-- Sam Patel   | sam@example.com   | 555-0178

DELETE FROM customers
WHERE id NOT IN (
  SELECT id FROM (
    SELECT MIN(id) AS id FROM customers GROUP BY name, email, phone
  ) AS keepers
);

-- Output (customers after the DELETE):
-- id | name        | email             | phone
-- ---+-------------+-------------------+---------
-- 1  | Maria Lopez | maria@example.com | 555-0142
-- 2  | Sam Patel   | sam@example.com   | 555-0178
-- 4  | Lena Novak  | lena@example.com  | 555-0121

Regras importantes

  • Liste as colunas que tornam duas linhas duplicadas. Deixe de fora o id e qualquer outra coisa que seja sempre diferente, como um timestamp created_at. Linhas que diferem em qualquer coluna listada são todas mantidas.
  • O wrapper SELECT id FROM (...) AS keepers é para o MySQL, que de outra forma não permite que um DELETE leia a própria tabela em uma subconsulta: “You can’t specify target table ‘customers’ for update in FROM clause”.
  • Confira antes de excluir. Execute primeiro a consulta com GROUP BY ou ROW_NUMBER() para ver o que será removido, e faça a exclusão dentro de uma transação que você possa desfazer com rollback.
  • Evite novas duplicatas com um índice único depois que a tabela estiver limpa:
CREATE UNIQUE INDEX customers_email_key ON customers (email);

INSERT INTO customers VALUES (6, 'Maria Lopez', 'maria@example.com', '555-0142');
-- ERROR: duplicate key value violates unique constraint "customers_email_key"

Sintaxe alternativa

Em código SQL Server, é comum ver as cópias numeradas em uma CTE e excluídas por meio dela, algo que só o SQL Server permite. Na tabela customers original:

-- SQL Server
WITH numbered AS (
  SELECT *, ROW_NUMBER() OVER (
    PARTITION BY name, email, phone ORDER BY id
  ) AS row_num
  FROM customers
)
DELETE FROM numbered WHERE row_num > 1;

-- Output (customers after the DELETE):
-- id | name        | email             | phone
-- ---+-------------+-------------------+---------
-- 1  | Maria Lopez | maria@example.com | 555-0142
-- 2  | Sam Patel   | sam@example.com   | 555-0178
-- 4  | Lena Novak  | lena@example.com  | 555-0121

Para combinar duas consultas sem repetir linhas, use UNION, que remove duplicatas, em vez de UNION ALL, que as mantém:

SELECT 'apple' AS fruit UNION ALL SELECT 'apple';

-- Output:
-- fruit
-- -----
-- apple
-- apple

SELECT 'apple' AS fruit UNION SELECT 'apple';
-- Output: apple

Quando você deve remover duplicatas?

Às vezes você só precisa ocultar repetições em um resultado; outras vezes, a própria tabela precisa de limpeza. Estes são os passos habituais, da verificação à exclusão.

Mostrar cada valor uma vez

Para um relatório, um dropdown ou uma verificação rápida do que há em uma coluna, SELECT DISTINCT remove as repetições do resultado e deixa a tabela como está.

Conte as cópias antes de excluir

Agrupe pelas colunas que definem uma duplicata e mantenha os grupos com HAVING COUNT(*) > 1. Isso mostra o que está duplicado e quantas vezes, antes de qualquer remoção. O guia para encontrar duplicatas em SQL traz mais formas de verificar.

Escolha qual cópia manter

ROW_NUMBER() numera as linhas em cada grupo de duplicatas. O ORDER BY dentro de OVER (...) decide qual linha recebe o número 1 e permanece: a mais antiga, a mais recente ou a mais completa.

Exclua as cópias extras

Depois de saber qual linha manter, exclua as outras. Para manter a linha mais recente em vez da mais antiga, numere as linhas por data, da mais recente para a mais antiga, e exclua tudo com número acima de 1.

Exemplos reais de remoção de duplicatas

Todos os países e transportadoras com que você trabalha

DISTINCT se aplica à linha inteira das colunas selecionadas, então Canada aparece uma vez para cada transportadora:

-- Input: shipments
-- order_id | country | carrier
-- ---------+---------+--------
-- 1001     | Canada  | UPS
-- 1002     | Germany | DHL
-- 1003     | Canada  | FedEx
-- 1004     | Canada  | UPS
-- 1005     | Germany | DHL

SELECT DISTINCT country, carrier
FROM shipments
ORDER BY country, carrier;

-- Output:
-- country | carrier
-- --------+--------
-- Canada  | FedEx
-- Canada  | UPS
-- Germany | DHL

Endereços de e-mail que diferem apenas em maiúsculas e minúsculas

Agrupe pelo e-mail em minúsculas para que Jon@Example.com e jon@example.com contem como cópias. (MySQL e SQL Server já ignoram maiúsculas e minúsculas por padrão, e LOWER() não causa problemas neles.)

-- Input: accounts
-- id | email
-- ---+----------------------
-- 1  | Ana.Silva@example.com
-- 2  | jon@example.com
-- 3  | ana.silva@example.com
-- 4  | Jon@Example.com
-- 5  | mei@example.com

SELECT LOWER(email) AS email, COUNT(*) AS copies
FROM accounts
GROUP BY LOWER(email)
HAVING COUNT(*) > 1
ORDER BY email;

-- Output:
-- email                 | copies
-- ----------------------+-------
-- ana.silva@example.com | 2
-- jon@example.com       | 2

Mantenha a cópia que tem telefone

Ordene primeiro as linhas que têm telefone e depois por id, para que a linha mais completa de cada grupo seja a número 1:

-- Input: contacts
-- id | email            | phone
-- ---+------------------+---------
-- 1  | ravi@example.com | NULL
-- 2  | ravi@example.com | 555-0110
-- 3  | ines@example.com | 555-0133
-- 4  | ines@example.com | NULL

SELECT
  id,
  email,
  phone,
  ROW_NUMBER() OVER (
    PARTITION BY email
    ORDER BY CASE WHEN phone IS NULL THEN 1 ELSE 0 END, id
  ) AS row_num
FROM contacts
ORDER BY email, row_num;

-- Output:
-- id | email            | phone    | row_num
-- ---+------------------+----------+--------
-- 3  | ines@example.com | 555-0133 | 1
-- 4  | ines@example.com | NULL     | 2
-- 2  | ravi@example.com | 555-0110 | 1
-- 1  | ravi@example.com | NULL     | 2

Excluir as linhas com número 2 ou maior (ids 1 e 4) deixa um contato completo por e-mail.

Exclua cópias exatas de uma tabela sem id

Quando as cópias são idênticas em todas as colunas, não há id para manter o menor. Copie as linhas distintas para uma nova tabela e substitua a antiga por ela. Recrie os índices e constraints que a tabela antiga tinha, pois a cópia não os mantém:

-- Input: page_views
-- url      | viewed_at
-- ---------+--------------------
-- /pricing | 2026-10-01 09:00:00
-- /pricing | 2026-10-01 09:00:00
-- /docs    | 2026-10-01 09:05:00
-- /pricing | 2026-10-01 09:00:00

-- In SQL Server, use SELECT DISTINCT * INTO page_views_clean FROM page_views,
-- then EXEC sp_rename 'page_views_clean', 'page_views'
CREATE TABLE page_views_clean AS SELECT DISTINCT * FROM page_views;
DROP TABLE page_views;
ALTER TABLE page_views_clean RENAME TO page_views;

-- Output (page_views afterwards):
-- url      | viewed_at
-- ---------+--------------------
-- /pricing | 2026-10-01 09:00:00
-- /docs    | 2026-10-01 09:05:00

Leitura complementar sobre remoção de duplicatas

Neste blog:

Documentação oficial:

Beekeeper Studio é um cliente de banco de dados gratuito e open source

A melhor ferramenta de consultas e edição de SQL que já usei. Tem tudo o que preciso para gerenciar meu banco de dados. - ⭐⭐⭐⭐⭐ Mit

O Beekeeper Studio é rápido, intuitivo e fácil de usar. Ele suporta vários bancos de dados e funciona muito bem no Windows, Mac e Linux.

A versão do Beekeeper para Linux tem 100% dos recursos, sem atalhos e sem concessões.

O que os usuários dizem sobre o Beekeeper Studio

★★★★★
"O Beekeeper Studio substituiu completamente meu antigo fluxo de trabalho com SQL. É rápido, intuitivo e torna o trabalho com bancos de dados agradável de novo."
— Alex K., desenvolvedor de banco de dados
★★★★★
"Já experimentei muitas GUIs de banco de dados, mas o Beekeeper encontra o equilíbrio perfeito entre recursos e simplicidade. Simplesmente funciona."
— Sarah M., engenheira full stack

Pronto para melhorar seu fluxo de trabalho com SQL?

download Baixe grátis