Ето седем начина за връщане на дублиращи се редове в MariaDB, когато тези редове имат първичен ключ или друга колона с уникален идентификатор.
Следователно дублиращите се редове споделят абсолютно еднакви стойности във всички колони, с изключение на колоната с уникален идентификатор.
Примерни данни
Ще използваме следните данни за нашите примери:
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 | +-------+-----------+----------+
Първите два реда са дублирани (с изключение на DogId
колона, която е първичен ключ на таблицата и съдържа уникална стойност във всички редове). Последните три реда също са дублирани (с изключение на DogId
колона).
Колоната с първичен ключ гарантира, че няма дублиращи се редове, което обикновено е добро нещо в RDBMS. По дефиниция обаче това означава, че няма дубликати. В нашия случай колоната с първичен ключ е нарастващо число и стойността му няма значение и не е значима. Следователно трябва да игнорираме този ред, ако искаме да намерим дубликати в колоните, които са значителен.
Опция 1
Можем да използваме GROUP BY
клауза, за да групирате колоните по значимите им колони, след което използвайте COUNT()
функция за връщане на броя на еднакви редове:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Резултат:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Ruff | Robinson | 1 | | Wag | Johnson | 3 | | Woof | Jones | 1 | +-----------+----------+-------+
Успяхме да изключим колоната с първичен ключ, като я пропуснем от нашата заявка.
Резултатът ни казва, че има два реда, съдържащи Барк Смит и три реда, съдържащи Уаг Джонсън. Това са дубликати (или три екземпляра в случая на Уаг Джонсън). Другите два реда нямат дубликати.
Опция 2
Можем да изключим недубликатите от изхода с HAVING
клауза:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Резултат:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Wag | Johnson | 3 | +-----------+----------+-------+
Опция 3
Също така е възможно да се провери за дубликати на свързани колони. Например, можем да използваме CONCAT()
функция за свързване на нашите две колони, използвайте DISTINCT
ключова дума, за да получите различни стойности, след това използвайте COUNT()
функция за връщане на броя:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Резултат:
+---------------+-------+ | DogName | Count | +---------------+-------+ | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+-------+
Опция 4
Можем да използваме ROW_NUMBER()
функция с PARTITION BY
клауза:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Резултат:
+-------+-----------+----------+------------+ | DogId | FirstName | LastName | Row_Number | +-------+-----------+----------+------------+ | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 6 | Wag | Johnson | 1 | | 5 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +-------+-----------+----------+------------+
Това създава нова колона с номер на ред, който се увеличава всеки път, когато има дубликат, но се нулира отново, когато има уникален ред.
В този случай не групираме резултатите, което означава, че можем да видим всеки дублиран ред, включително колоната с уникален идентификатор.
Опция 5
Можем също да използваме предишния пример като общ табличен израз в по-голяма заявка:
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 | | 5 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +-------+-----------+----------+------------+
Това изключва недубликатите от изхода и изключва един ред от всеки дубликат от изхода.
Тази заявка може да се използва като предшественик на операция за премахване на дупиране. Може да ни покаже какво ще бъде изтрито, ако решим да изтрием дубликати. За да премахнем фалшифицирането на таблицата, всичко, което трябва да направим, е да заменим последния SELECT *
с DELETE
.
Опция 6
Ето по-сбит начин да получите същия изход като предишния пример:
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 | +-------+-----------+----------+
Този пример не изисква генериране на наш отделен номер на ред.
Можем да заменим SELECT *
с DELETE
за да изтриете дубликатите.
Опция 7
И накрая, ето още една опция за връщане на дубликати:
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 | +-------+-----------+----------+-------+-----------+----------+