Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

7 sposobów na znalezienie zduplikowanych wierszy w SQL Server, ignorując dowolny klucz podstawowy

Oto siedem opcji znajdowania zduplikowanych wierszy w SQL Server, gdy te wiersze mają klucz podstawowy lub inną kolumnę unikatowego identyfikatora.

Innymi słowy, tabela zawiera co najmniej dwa wiersze, które mają dokładnie te same wartości we wszystkich kolumnach, z wyjątkiem kolumny z unikalnym identyfikatorem.

Przykładowe dane

Załóżmy, że mamy tabelę z następującymi danymi:

SELECT * FROM Dogs;

Wynik:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
| 6       | Wag         | Johnson    |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Widzimy, że pierwsze dwa wiersze są duplikatami (z wyjątkiem DogId kolumna, która zawiera unikatową wartość we wszystkich wierszach i może być używana jako kolumna klucza podstawowego tabeli). Widzimy również, że ostatnie trzy wiersze są duplikatami (z wyjątkiem DogId kolumna).

Kolumna unikalnego identyfikatora zapewnia, że ​​nie ma zduplikowanych wierszy, co jest zwykle bardzo pożądaną cechą w systemach RDBMS. Jednak w tym przypadku może to zakłócić naszą zdolność do znajdowania duplikatów. Z definicji kolumna unikalnego identyfikatora gwarantuje, że nie ma duplikatów. Na szczęście możemy dość łatwo rozwiązać ten problem, jak pokazują poniższe przykłady.

Opcja 1

Prawdopodobnie najłatwiejszym/najprostszym sposobem na to jest proste zapytanie, które używa GROUP BY klauzula:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;

Wynik:

+-------------+------------+---------+
| FirstName   | LastName   | Count   |
|-------------+------------+---------|
| Wag         | Johnson    | 3       |
| Woof        | Jones      | 1       |
| Ruff        | Robinson   | 1       |
| Bark        | Smith      | 2       |
+-------------+------------+---------+

Udało nam się wykluczyć kolumnę klucza podstawowego/unikalnego identyfikatora, pomijając ją w naszym zapytaniu.

Wynik mówi nam, że istnieją trzy wiersze zawierające Wag Johnson i dwa wiersze zawierające Bark Smith. Są to duplikaty (lub trzy egzemplarze w przypadku Wag Johnson).

Opcja 2

Możemy wykluczyć nieduplikaty z wyniku, dołączając HAVING klauzula w naszym zapytaniu:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;

Wynik:

+-------------+------------+---------+
| FirstName   | LastName   | Count   |
|-------------+------------+---------|
| Wag         | Johnson    | 3       |
| Bark        | Smith      | 2       |
+-------------+------------+---------+

Opcja 3

Możemy również sprawdzić duplikaty w połączonych kolumnach. Na przykład możemy użyć CONCAT() funkcja łącząca nasze dwie kolumny:

SELECT
    DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
    COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);

Wynik:

+---------------+---------+
| DogName       | Count   |
|---------------+---------|
| Bark Smith    | 2       |
| Ruff Robinson | 1       |
| Wag Johnson   | 3       |
| Woof Jones    | 1       |
+---------------+---------+

Opcja 4

Możemy użyć ROW_NUMBER() funkcja z PARTITION BY klauzula, aby utworzyć nową kolumnę z numerem wiersza, który zwiększa się za każdym razem, gdy pojawia się duplikat, ale resetuje się ponownie, gdy istnieje unikalny wiersz:

SELECT 
    *,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS Row_Number
FROM Dogs;

Wynik:

+---------+-------------+------------+--------------+
| DogId   | FirstName   | LastName   | Row_Number   |
|---------+-------------+------------+--------------|
| 1       | Bark        | Smith      | 1            |
| 2       | Bark        | Smith      | 2            |
| 4       | Ruff        | Robinson   | 1            |
| 5       | Wag         | Johnson    | 1            |
| 6       | Wag         | Johnson    | 2            |
| 7       | Wag         | Johnson    | 3            |
| 3       | Woof        | Jones      | 1            |
+---------+-------------+------------+--------------+

Jedną z zalet tej metody jest to, że możemy zobaczyć każdy zduplikowany wiersz wraz z jego kolumną unikatowego identyfikatora, ponieważ nie grupujemy wyników.

Opcja 5

Możemy również użyć poprzedniego przykładu jako wspólnego wyrażenia tabelowego w większym zapytaniu:

WITH cte AS 
    (
        SELECT 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Wynik:

+---------+-------------+------------+--------------+
| DogId   | FirstName   | LastName   | Row_Number   |
|---------+-------------+------------+--------------|
| 2       | Bark        | Smith      | 2            |
| 6       | Wag         | Johnson    | 2            |
| 7       | Wag         | Johnson    | 3            |
+---------+-------------+------------+--------------+

Ta opcja wyklucza z danych wyjściowych nieduplikaty.

Wyklucza również z danych wyjściowych dokładnie jeden wiersz każdego duplikatu. To otwiera nam drzwi do przekręcenia ostatniego SELECT * w DELETE aby usunąć duplikat tabeli, zachowując po jednym z każdego duplikatu.

Opcja 6

Oto bardziej zwięzły sposób na uzyskanie tego samego wyniku, co w poprzednim przykładzie:

SELECT * FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Wynik:

+-------+-----------+----------+
| DogId | FirstName | LastName |
+-------+-----------+----------+
|     2 | Bark      | Smith    |
|     6 | Wag       | Johnson  |
|     7 | Wag       | Johnson  |
+-------+-----------+----------+

Ten przykład nie wymaga generowania własnego oddzielnego numeru wiersza.

Opcja 7

I na koniec, oto nieco bardziej skomplikowana technika zwracania zduplikowanych wierszy:

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
);

Wynik:

+---------+-------------+------------+---------+-------------+------------+
| DogId   | FirstName   | LastName   | DogId   | FirstName   | LastName   |
|---------+-------------+------------+---------+-------------+------------|
| 2       | Bark        | Smith      | 1       | Bark        | Smith      |
| 7       | Wag         | Johnson    | 5       | Wag         | Johnson    |
| 7       | Wag         | Johnson    | 6       | Wag         | Johnson    |
+---------+-------------+------------+---------+-------------+------------+

Nawet wynik wygląda na bardziej zawiły, ale hej, nadal pokazuje nam duplikaty!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. RADIANS() Przykłady w SQL Server

  2. Aktywne sesje i stan programu SQL Server

  3. Zwróć typ wyzwalacza DML w tabeli w SQL Server

  4. Konwersja DateTime do formatu RRRR-MM-DD w SQL Server

  5. Konwersja daty i kultura:różnica między DATE a DATETIME