Följande exempel använder T-SQL för att ta bort dubbletter av rader i SQL Server samtidigt som primärnyckeln eller den unika identifierarkolumnen ignoreras.
Mer specifikt tar exemplen bort dubbletter av rader men behåller en. Så, givet två identiska rader, raderas en och den andra finns kvar. Detta hänvisas ofta till som "de-dupera" tabellen, "deduplicering" av tabellen, etc.
Exempeldata
Anta att vi har en tabell med följande data:
SELECT * FROM Dogs;
Resultat:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +---------+-------------+------------+
Vi kan se att de två första raderna är dubbletter, och det är de tre sista raderna också.
Alternativ 1
Låt oss först köra följande kod för att kontrollera vilka rader som kommer att deduperas:
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;
Resultat:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +---------+-------------+------------+--------------+
Vi använde ROW_NUMBER()
funktion med PARTITION BY
sats för att skapa vårt eget radnummer som ökar när några dubbletter hittas och återställs när en icke-duplicerad hittas. Ett nummer större än 1 indikerar att det är en dubblett, och därför returnerar vi bara rader som har ett nummer större än 1.
Vi kan se att tre rader kommer att raderas när vi de-duperar den här tabellen.
Låt oss nu de-dupera tabellen:
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;
Resultat:
(3 rows affected)
Som väntat togs tre rader bort.
Den här frågan är nästan identisk med den föregående. Allt vi gjorde var att ändra SELECT *
på sista raden till DELETE
.
Låt oss nu välja alla rader från tabellen för att verifiera att rätt rader har tagits bort:
SELECT * FROM Dogs;
Resultat:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | +---------+-------------+------------+
Vi kan se att varje hund nu bara visas en gång i tabellen.
Alternativ 2
Förutsatt att tabellen har återställts efter föregående exempel, här är ett annat sätt att leta efter dubbletter:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultat:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +---------+-------------+------------+
I det här fallet använde vi EXCEPT
operatorn tillsammans med MIN()
fungera. Vi skulle kunna ersätta MIN()
med MAX()
beroende på vilka rader vi vill ska raderas.
För att radera raderna kan vi helt enkelt ersätta SELECT *
med DELETE
:
DELETE FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultat:
(3 rows affected)
Och kolla för att se vad som finns kvar:
SELECT * FROM Dogs;
Resultat:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | +---------+-------------+------------+
Alternativ 3
Ett annat sätt att göra det på är att gå med i tabellen på sig själv och leta efter dubbletter på det sättet.
Förutsatt att tabellen har återställts efter föregående exempel, här är vårt tredje alternativ för att välja dubbletter:
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
);
Resultat:
+---------+-------------+------------+---------+-------------+------------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | |---------+-------------+------------+---------+-------------+------------| | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +---------+-------------+------------+---------+-------------+------------+
Detta resultat är inte riktigt lika tydligt som det i föregående exempel, men vi kan fortfarande se vilka rader som är dubbletter.
Nu kan vi ändra den frågan så att vi tar bort dubbletter av rader:
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
)
);
Resultat:
(3 rows affected)
Återigen togs tre rader bort.
Låt oss kolla tabellen igen:
SELECT * FROM Dogs;
Resultat:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 7 | Wag | Johnson | +---------+-------------+------------+
Du kanske märker att den här gången togs de andra raderna bort. Med andra ord har vi nu DogId
s 2, 3, 4 och 7 medan vi i de tidigare exemplen hade 1, 3, 4 och 5.
Vi kan enkelt ändra detta exempel för att ta bort samma rader som de tidigare exemplen. För att göra detta kan vi använda MIN()
funktion istället för MAX()
funktion:
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
)
);