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

6 maneiras de selecionar linhas duplicadas no Oracle


Os exemplos a seguir retornam linhas duplicadas de uma tabela do Oracle Database.

Dados de amostra


Suponha que temos uma tabela com os seguintes dados:
SELECT * FROM Pets;

Resultado:
PetId  PetName  PetType
-----  -------  -------
1      Wag      Dog    
1      Wag      Dog    
2      Scratch  Cat    
3      Tweet    Bird   
4      Bark     Dog    
4      Bark     Dog    
4      Bark     Dog    

As duas primeiras linhas são duplicadas, assim como as três últimas linhas. Nesse caso, as linhas duplicadas contêm valores duplicados em todas as colunas, incluindo a coluna ID.

Opção 1


Podemos usar a seguinte consulta para ver quantas linhas são duplicadas:
SELECT 
    PetId,
    PetName,
    PetType,
    COUNT(*) AS "Count"
FROM Pets
GROUP BY 
    PetId,
    PetName,
    PetType
ORDER BY PetId;

Resultado:
PETID	PETNAME	PETTYPE	Count
1	Wag	Dog	2
2	Scratch	Cat	1
3	Tweet	Bird	1
4	Bark	Dog	3

Agrupamos as linhas por todas as colunas e retornamos a contagem de linhas de cada grupo. Qualquer linha com uma contagem maior que 1 é uma duplicata.

Podemos ordená-lo por contagem em ordem decrescente, para que as linhas com mais duplicatas apareçam primeiro:
SELECT 
    PetId,
    PetName,
    PetType,
    COUNT(*) AS "Count"
FROM Pets
GROUP BY 
    PetId,
    PetName,
    PetType
ORDER BY Count(*) DESC;

Resultado:
PETID	PETNAME	PETTYPE	Count
4	Bark	Dog	3
1	Wag	Dog	2
2	Scratch	Cat	1
3	Tweet	Bird	1

Opção 2


Se quisermos apenas as linhas duplicadas listadas, podemos usar o HAVING cláusula para retornar apenas linhas com uma contagem maior que 1:
SELECT 
    PetId,
    PetName,
    PetType,
    COUNT(*) AS "Count"
FROM Pets
GROUP BY 
    PetId,
    PetName,
    PetType
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC;

Resultado:
PETID	PETNAME	PETTYPE	Count
4	Bark	Dog	3
1	Wag	Dog	2

Opção 3


Outra opção é usar o ROW_NUMBER() função da janela:
SELECT 
    PetId,
    PetName,
    PetType,
    ROW_NUMBER() OVER ( 
        PARTITION BY PetId, PetName, PetType 
        ORDER BY PetId, PetName, PetType
        ) AS rn
FROM Pets;

Resultado:
PETID	PETNAME	PETTYPE	RN
1	Wag	Dog	1
1	Wag	Dog	2
2	Scratch	Cat	1
3	Tweet	Bird	1
4	Bark	Dog	1
4	Bark	Dog	2
4	Bark	Dog	3

A PARTITION BY cláusula divide o conjunto de resultados produzido pelo FROM cláusula em partições às quais a função é aplicada. Quando especificamos partições para o conjunto de resultados, cada partição faz com que a numeração comece novamente (ou seja, a numeração começará em 1 para a primeira linha de cada partição).

Opção 4


Podemos usar a consulta acima como uma expressão de tabela comum:
WITH cte AS 
    (
        SELECT 
            PetId,
            PetName,
            PetType,
            ROW_NUMBER() OVER ( 
                PARTITION BY PetId, PetName, PetType 
                ORDER BY PetId, PetName, PetType
                ) AS Row_Number
        FROM Pets
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Resultado:
PETID	PETNAME	PETTYPE	ROW_NUMBER
1	Wag	Dog	2
4	Bark	Dog	2
4	Bark	Dog	3

Isso retorna apenas as linhas em excesso das duplicatas correspondentes. Portanto, se houver duas linhas idênticas, ele retornará uma delas. Se houver três linhas idênticas, ele retornará duas e assim por diante.

Opção 5


Dado que nossa tabela não contém uma coluna de chave primária, podemos aproveitar o rowid do Oracle pseudocoluna:
SELECT * FROM Pets
WHERE EXISTS (
  SELECT 1 FROM Pets p2 
  WHERE Pets.PetName = p2.PetName
  AND Pets.PetType = p2.PetType
  AND Pets.rowid > p2.rowid
);

Resultado:
PETID	PETNAME	PETTYPE
1	Wag	Dog
4	Bark	Dog
4	Bark	Dog

A maneira como isso funciona é que cada linha em um banco de dados 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. No entanto, é importante observar que linhas em tabelas diferentes armazenadas juntas no mesmo cluster podem ter o mesmo rowid .

Um benefício do exemplo acima é que podemos substituir SELECT * com DELETE para desduplicar a tabela.

Opção 6


E finalmente, aqui está outra opção que usa o rowid pseudocoluna:
SELECT * FROM Pets
WHERE rowid > (
  SELECT MIN(rowid) FROM Pets p2  
  WHERE Pets.PetName = p2.PetName
  AND Pets.PetType = p2.PetType
);

Resultado:
PETID	PETNAME	PETTYPE
1	Wag	Dog
4	Bark	Dog
4	Bark	Dog

Mesmo resultado do exemplo anterior.

Assim como no exemplo anterior, podemos substituir SELECT * com DELETE para remover linhas duplicadas da tabela.