Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

11 maneiras de encontrar linhas duplicadas que possuem uma chave primária no Oracle


Aqui estão onze opções para retornar linhas duplicadas no Oracle Database quando essas linhas têm uma chave primária ou alguma outra coluna de identificador exclusivo e você deseja ignorá-la.

Dados de amostra


Usaremos os seguintes dados para nossos exemplos:
SELECT * FROM Dogs;

Resultado:
DOGID PRIMEIRO NOME SOBRENOME
1 Latido Smith
2 Latido Smith
3 Au Jones
4 Ruff Robinson
5 Agite Johnson
6 Agite Johnson
7 Agite Johnson

As duas primeiras linhas são duplicadas e as três últimas linhas são duplicadas. As linhas duplicadas compartilham exatamente os mesmos valores em todas as colunas, com exceção da coluna de chave primária/ID exclusivo.

A coluna de chave primária garante que não haja linhas duplicadas, o que é uma boa prática em RDBMSs, pois as chaves primárias ajudam a reforçar a integridade dos dados. Mas o fato de as chaves primárias conterem valores únicos significa que precisamos ignorar essa coluna ao procurar por duplicatas.

Em nossa tabela acima, a coluna de chave primária é um número crescente e seu valor não tem significado e não é significativo. Podemos, portanto, ignorar os dados dessa coluna ao procurar duplicatas.

Opção 1


Aqui está nossa primeira opção para retornar duplicatas:
SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;

Resultado:
FIRSTNAME SOBRENOME COUNT
Agite Johnson 3
Latido Smith 2
Ruff Robinson 1
Uau Jones 1

Aqui construímos nossa consulta com o GROUP BY cláusula para que a saída seja agrupada pelas colunas relevantes. Também usamos o COUNT() função para retornar o número de linhas idênticas. E ordenamos por contagem em ordem decrescente para que as duplicatas apareçam primeiro.

O resultado nos diz que existem três linhas contendo Wag Johnson e duas linhas contendo Bark Smith. Estes são duplicados (ou triplicados no caso de Wag Johnson). As outras duas linhas não têm duplicatas.

Opção 2


Podemos adicionar o HAVING cláusula ao nosso exemplo anterior para excluir não duplicados da saída:
SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC;

Resultado:
FIRSTNAME SOBRENOME COUNT
Agite Johnson 3
Latido Smith 2

Opção 3


Também podemos verificar duplicatas em colunas concatenadas. Neste caso, usamos o DISTINCT palavra-chave para obter valores distintos, então use o COUNT() função para retornar a contagem:
SELECT
    DISTINCT FirstName || ' ' || LastName AS DogName,
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC;

Resultado:
NOME DO CÃO COUNT
Wag Johnson 3
Bark Smith 2
Ruff Robinson 1
Woof Jones 1

Opção 4


Cada linha no Oracle tem um rowid pseudocoluna que retorna o endereço da linha. O rowid é um identificador exclusivo para linhas na tabela e geralmente seu valor identifica exclusivamente uma linha no banco de dados (embora seja importante observar que linhas em tabelas diferentes armazenadas juntas no mesmo cluster podem ter o mesmo rowid ).

De qualquer forma, podemos construir uma consulta que usa o rowid se nós quisermos:
SELECT * FROM Dogs
WHERE EXISTS (
  SELECT 1 FROM Dogs d2 
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
  AND Dogs.rowid > d2.rowid
);

Resultado:
DOGID PRIMEIRO NOME SOBRENOME
2 Latido Smith
6 Agite Johnson
7 Agite Johnson

Poderíamos substituir o SELECT * com EXCLUIR para realizar uma operação de desduplicação na mesa.

Observe que poderíamos ter usado o DogId coluna (nossa chave primária) em vez do rowid se quiséssemos. Dito isso, o rowid pode ser útil se você não puder usar a coluna de chave primária por algum motivo ou se a tabela não tiver uma chave primária.

Opção 5


Aqui está outra consulta que usa o rowid :
SELECT * FROM Dogs
WHERE rowid > (
  SELECT MIN(rowid) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Resultado:
DOGID PRIMEIRO NOME SOBRENOME
2 Latido Smith
6 Agite Johnson
7 Agite Johnson

Assim como no exemplo anterior, poderíamos substituir o SELECT * com EXCLUIR para excluir as linhas duplicadas.

Opção 6


Os dois rowid as opções acima são ótimas se você deve ignorar completamente a chave primária em sua consulta (ou se você não tiver uma coluna de chave primária). No entanto, como mencionado, ainda há a opção de substituir rowid com a coluna de chave primária – no nosso caso o DogId coluna:
SELECT * FROM Dogs
WHERE EXISTS (
  SELECT 1 FROM Dogs d2 
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
  AND Dogs.DogId > d2.DogId
);

Resultado:
DOGID PRIMEIRO NOME SOBRENOME
2 Latido Smith
6 Agite Johnson
7 Agite Johnson

Opção 7


E aqui está a outra consulta com o rowid substituído pelo DogId coluna:
SELECT * FROM Dogs
WHERE DogId > (
  SELECT MIN(DogId) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Resultado:
DOGID PRIMEIRO NOME SOBRENOME
2 Latido Smith
6 Agite Johnson
7 Agite Johnson

Opção 8


Outra maneira de encontrar duplicatas é usar o ROW_NUMBER() função da janela:
SELECT 
    DogId,
    FirstName,
    LastName,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS row_num
FROM Dogs;

Resultado:
DOGID PRIMEIRO NOME SOBRENOME ROW_NUM
1 Latido Smith 1
2 Latido Smith 2
4 Ruff Robinson 1
7 Agite Johnson 1
5 Agite Johnson 2
6 Agite Johnson 3
3 Au Jones 1

Usando a PARTIÇÃO cláusula resulta na adição de uma nova coluna, com um número de linha que aumenta cada vez que há uma duplicata, mas é redefinido novamente quando há uma linha única.

Nesse caso, não agrupamos os resultados, o que significa que podemos ver cada linha duplicada, incluindo sua coluna de identificador exclusivo.

Opção 9


Também podemos usar o exemplo anterior como uma expressão de tabela comum em uma consulta maior:
WITH cte AS 
    (
        SELECT 
            DogId,
            FirstName,
            LastName,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS row_num
        FROM Dogs
    )
SELECT * FROM cte WHERE row_num <> 1;

Resultado:
DOGID PRIMEIRO NOME SOBRENOME ROW_NUM
2 Latido Smith 2
5 Agite Johnson 2
6 Agite Johnson 3

Essa consulta exclui não duplicados da saída e exclui uma linha de cada duplicata da saída.

Opção 10


Aqui está outra maneira de obter a mesma saída do exemplo anterior:
SELECT * FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    MINUS SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Resultado:
DOGID PRIMEIRO NOME SOBRENOME
2 Latido Smith
6 Agite Johnson
7 Agite Johnson

Este exemplo usa o MINUS do Oracle operador, que retorna apenas linhas exclusivas retornadas pela primeira consulta, mas não pela segunda.

O MENOS operador é semelhante ao EXCEPT em outros SGBDs, como SQL Server, MariaDB, PostgreSQL e SQLite.

Opção 11


Aqui está outra opção para selecionar duplicatas da nossa tabela:
SELECT * 
FROM Dogs d1, Dogs d2 
WHERE d1.FirstName = d2.FirstName 
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId 
AND d1.DogId = (
    SELECT MAX(DogId) 
    FROM Dogs d3 
    WHERE d3.FirstName = d1.FirstName 
    AND d3.LastName = d1.LastName
);

Resultado:
DOGID PRIMEIRO NOME SOBRENOME CÃO PRIMEIRO NOME SOBRENOME
2 Latido Smith 1 Latido Smith
7 Agite Johnson 5 Agite Johnson
7 Agite Johnson 6 Agite Johnson