Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

3 начина за изтриване на дублиращи се редове в SQL Server, като игнорирате първичния ключ

Следните примери използват T-SQL за изтриване на дублиращи се редове в SQL Server, като игнорират първичния ключ или колоната с уникален идентификатор.

По-конкретно, примерите изтриват дублиращи се редове, но запазват един. И така, като се имат предвид два еднакви реда, единият се изтрива, а другият остава. Това често се нарича „дедупиране“ на таблицата, „дедупликация“ на таблицата и т.н.

Примерни данни

Да предположим, че имаме таблица със следните данни:

SELECT * FROM Dogs;

Резултат:

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

Можем да видим, че първите два реда са дублирани, както и последните три реда.

Опция 1

Първо, нека изпълним следния код, за да проверим кои редове ще бъдат премахнати:

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;

Резултат:

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

Използвахме ROW_NUMBER() функция с PARTITION BY клауза, за да създадем наш собствен номер на ред, който се увеличава, когато се намерят дубликати, и се нулира, когато се намери недубликат. Число, по-голямо от 1, показва, че е дубликат и затова връщаме само редове, които имат число, по-голямо от 1.

Можем да видим, че три реда ще бъдат изтрити, когато премахнем дублирането на тази таблица.

Сега нека премахнем измамата на таблицата:

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

Резултат:

(3 rows affected)

Както се очакваше, три реда бяха изтрити.

Тази заявка е почти идентична с предишната. Всичко, което направихме, беше да променим SELECT * на последния ред до DELETE .

Сега нека изберем всички редове от таблицата, за да проверим дали правилните редове са изтрити:

SELECT * FROM Dogs;

Резултат:

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

Можем да видим, че всяко куче сега се появява само веднъж в таблицата.

Опция 2

Ако приемем, че таблицата е била възстановена след предишния пример, ето друг начин за проверка за дубликати:

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

Резултат:

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

В този случай използвахме EXCEPT оператор заедно с MIN() функция. Бихме могли да заменим MIN() с MAX() в зависимост от това кои редове искаме да бъдат изтрити.

За да изтрием редовете, можем просто да заменим SELECT * с DELETE :

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

Резултат:

(3 rows affected)

И проверете какво остава:

SELECT * FROM Dogs;

Резултат:

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

Опция 3

Друг начин да го направите е да присъедините таблицата към нея и да проверите за дубликати по този начин.

Ако приемем, че таблицата е била възстановена след предишния пример, ето нашата трета опция за избор на дубликати:

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

Резултат:

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

Този резултат не е толкова ясен като този в предишния пример, но все пак можем да видим кои редове са дублирани.

Сега можем да модифицираме тази заявка, така че да изтрием дублиращи се редове:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    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
    )
);

Резултат:

(3 rows affected)

Отново три реда бяха изтрити.

Нека отново проверим таблицата:

SELECT * FROM Dogs;

Резултат:

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

Може да забележите, че този път другите редове бяха изтрити. С други думи, сега имаме DogId s 2, 3, 4 и 7, докато в предишните примери бяхме оставени с 1, 3, 4 и 5.

Можем лесно да променим този пример, за да изтрием същите редове като предишните примери. За да направим това, можем да използваме MIN() функция вместо MAX() функция:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName 
    AND d1.DogId <> d2.DogId 
    AND d1.DogId=( 
        SELECT MIN(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    )
);

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как работи функцията QUOTENAME() в SQL Server (T-SQL)

  2. Как да четете и анализирате планове за изпълнение на SQL Server

  3. конвертирайте серийния номер на датата на Excel в обикновена дата

  4. Как да създадете таблица с помощта на заявка за избор в SQL Server?

  5. Как да използвате ВСЕКИ / НЯКОЙ логически оператор в SQL Server - SQL Server / TSQL урок, част 127