Existuje řada způsobů, jak z tabulky odstranit duplicitní řádky. Jedním z nich je využití analytické funkce spolu s CTE (Common Table Expression).
Pomocí analytické funkce ROW_NUMBER() získáme pro každý řádek číslo, které bude unikátní vždy v rámci dané partition, kterou v příkladu níže vytvoříme tak, že pomocí klauzule PARITION BY rozdělíme řádky do skupin podle hodnot ve sloupci Value1. V každé takto vytvořené skupině budou potom řádky očíslovány vzestupě od jedné.
Z takto vytvořené virtuální tabulky poté vybereme pouze řádky, které jsou první v každé skupině. Všechny ostatní a tedy duplicitní záznamy budou z výsledkové sady vyjmuty.
CREATE TABLE dbo.SampleTable (
Id INT,
Value1 VARCHAR(10)
)
GO
INSERT INTO dbo.SampleTable
SELECT 1, 'Val1' UNION ALL
SELECT 2, 'Val2' UNION ALL
SELECT 3, 'Val1' UNION ALL
SELECT 4, 'Val4'
GO
SELECT * FROM dbo.SampleTable
GO
;WITH cte AS
(
SELECT
*, ROW_NUMBER() OVER (PARTITION BY Value1 ORDER BY Id) RN
FROM dbo.SampleTable
)
DELETE FROM cte
WHERE RN > 1
GO
SELECT * FROM dbo.SampleTable
GO
V prvním případě jsme odstraňovali duplicitní řádky z tabulky, která neměla žádný primární klíč. Nyní si ukážeme, jak odstranit řádky z tabulky, která má primární klíč s IDENTITY(1,1). Můžeme použít metodu podobnou prvnímu příkladu (CTE) nebo jednoduchý dotaz s vnitřním dotazem ve WHERE podmínce.
-- create SampleTable
CREATE TABLE dbo.tblSampleTable
(
Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
ObjectId INT NOT NULL,
ObjectName SYSNAME NOT NULL
)
GO
-- populate sample data
INSERT INTO dbo.tblSampleTable
( ObjectId, ObjectName )
SELECT TOP(1000000) c1.object_id, c1.name
FROM master.sys.columns c1
CROSS JOIN master.sys.columns c2
CROSS JOIN master.sys.columns c3
GO
-- version 1
;WITH Dupl as
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ObjectId, ObjectName ORDER BY (SELECT NULL)) as RN
from dbo.tblSampleTable
)
DELETE FROM dbo.tblSampleTable
WHERE Id NOT IN (SELECT Id FROM Dupl WHERE RN = 1)
GO
-- version 2
DELETE FROM dbo.tblSampleTable
WHERE Id NOT IN
(
SELECT MIN(Id) Id
FROM dbo.tblSampleTable
GROUP BY ObjectId, ObjectName
)
GO
