Як я можу видалити повторювані рядки?


1284

Який найкращий спосіб видалити повторювані рядки з досить великої SQL Serverтаблиці (тобто 300 000+ рядків)?

Рядки, звичайно, не будуть ідеальними дублікатами через існування RowIDполя ідентичності.

MyTable

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

13
Коротка порада для користувачів PostgreSQL, які читають це (багато, залежить від того, як часто це пов’язано): Pg не виставляє терміни CTE як оновлені види, тому ви не DELETE FROMможете безпосередньо використовувати термін CTE. Дивіться stackoverflow.com/q/18439054/398670
Крейг Рінгер

@CraigRinger те ж саме стосується і Sybase - я зібрав тут інші рішення (повинні бути дійсними і для PG та інших: stackoverflow.com/q/19544489/1855801 (просто замініть ROWID()функцію стовпцем RowID, якщо такий є)
maf-soft

12
Просто додати тут застереження. Під час запуску будь-якого процесу дедуплікації завжди перевірте, що ви видаляєте спочатку! Це одна з тих областей, де дуже часто трапляється випадкове видалення хороших даних.
Джефф Девіс

Відповіді:


1142

Припускаючи , що ні анулює, то GROUP BYунікальні колони, і RowId як ряд , щоб зберегти. Потім просто видаліть усе, у якому не було ідентифікатора рядка:SELECTMIN (or MAX)

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

Якщо у вас GUID замість цілого числа, його можна замінити

MIN(RowId)

з

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))

327
Чи буде це добре також? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
Георг Шоллі

10
@Andriy - У SQL Server LEFT JOINменш ефективно, ніж NOT EXISTS sqlinthewild.co.za/index.php/2010/03/23/… Цей же сайт також порівнює NOT INпорівняно з NOT EXISTS. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in З 3 я думаю, що NOT EXISTSнайкраще. Усі троє будуть генерувати план із самозаключенням, хоча цього можна уникнути.
Мартін Сміт

12
@Martin, @Georg: Отже, я зробив невеликий тест. Була створена та заповнена велика таблиця, як описано тут: sqlinthewild.co.za/index.php/2010/03/23/… Після цього було вироблено два SELECT, один, що використовує лівий приєднатися +, де є NULL, інший, використовуючи кнопку NOT В одному. Тоді я приступив до планів виконання, і вгадайте, що? Витрати на запит склали 18% для LEFT JOIN проти 82% для NOT IN, для мене великий сюрприз. Я, можливо, зробив щось, чого не мав би, або навпаки, що, якщо це правда, я хотів би дуже знати.
Андрій М

16
@ GeorgSchölly дав елегантну відповідь. Я використовував це на таблиці, де моя помилка PHP створювала дублікати рядків.
Філіп Кірнс

12
Вибачте, але чому DELETE MyTable FROM MyTableправильний синтаксис? Я не бачу розміщення імені таблиці відразу після параметра DELETEяк опції в документації тут . Вибачте, якщо це очевидно для інших; Я новачок у SQL, просто намагаюся навчитися. Важливіше, ніж чому це працює: яка різниця між включенням назви таблиці там чи ні?
levininja

760

Ще один можливий спосіб цього зробити

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

Я використовую ORDER BY (SELECT 0)вище, оскільки це довільно, який рядок потрібно зберегти у випадку зв'язання.

Щоб зберегти найновіший RowID, щоб, наприклад, можна було його використовуватиORDER BY RowID DESC

Плани виконання

План виконання для цього часто простіший та ефективніший, ніж у прийнятій відповіді, оскільки він не вимагає самостійного приєднання.

Плани виконання

Однак це не завжди так. Одне місце, де GROUP BYрішення може бути кращим - це ситуації, коли хеш-агрегат вибирався б на користь потокового агрегату.

ROW_NUMBERРішення завжди буде давати в значній мірі той же план , тоді як GROUP BYстратегія є більш гнучкою.

Плани виконання

Фактори, які можуть сприяти хеш-сукупному підходу, були б

  • Немає корисного індексу на стовпчиках розділів
  • порівняно менше груп із відносно більшою кількістю дублікатів у кожній групі

У крайніх версіях цього другого випадку (якщо є дуже мало груп з багатьма дублікатами в кожній), можна також розглянути можливість просто вставити рядки для збереження в нову таблицю, потім TRUNCATE- копіювання оригіналу та копіювання їх назад, щоб мінімізувати ведення журналу порівняно зі видаленням дуже висока частка рядів.


28
Якщо я можу додати: прийнята відповідь не працює з таблицями, які використовують uniqueidentifier. Цей набагато простіше і прекрасно працює на будь-якому столі. Дякую, Мартіне.
BrunoLM

15
Це така дивовижна відповідь! Це спрацювало подія, коли я видалив старий ПК перед тим, як зрозумів там, де дублікати. +100
Мікаель Еліассон

12
Я пропоную запитати, а потім відповісти на це питання (з цією відповіддю) на DBA.SE. Тоді ми можемо додати його до нашого списку канонічних відповідей .
Нік Чаммас

16
На відміну від прийнятої відповіді, це також працювало над таблицею, яка не мала ключа ( RowId) для порівняння.
vossad01

8
Ця система працює не у всіх версіях сервера SQL, з іншого боку
Девід

150

На веб-сайті підтримки Microsoft є добра стаття про видалення дублікатів . Це досить консервативно - вони змушують вас робити все окремими кроками - але це повинно добре працювати проти великих столів.

Раніше я використовував самоз'єднання для цього, хоча це, можливо, було б видозмінено за допомогою клавіші HAVING:

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField

ідеально! Я виявив, що це найефективніший спосіб видалення повторюваних рядків у моїй старій версії mariadb 10.1.xx. Дякую тобі!
П’яний М

Набагато простіше і простіше зрозуміти!
Марк

98

Наступний запит корисний для видалення повторюваних рядків. Таблиці в цьому прикладі , мають в IDякості стовпчика ідентифікації , а стовпці , які мають дублюючі дані є Column1, Column2і Column3.

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

Наступний скрипт показує використання GROUP BY, HAVING, ORDER BYв одному запиті, і повертає результати з повторюваним шпальти і його підрахунку.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 

1
Помилка MySQL з першим сценарієм "Ви не можете вказати цільову таблицю" TableName "для оновлення в пункті FROM"
D.Rosado

Крім помилки D.Rosado, про яку ви вже повідомляли, ваш перший запит також дуже повільний. Відповідний запит SELECT зайняв мою настройку + - в 20 разів довше прийнятої відповіді.
parvus

8
@parvus - питання позначене тегом SQL Server, а не MySQL. Синтаксис відмінний у SQL Server. Також MySQL, як відомо, погано оптимізує підзапити, дивіться, наприклад, тут . Ця відповідь чудова в SQL Server. Насправді NOT INчасто працює краще, ніж OUTER JOIN ... NULL. Я б додав HAVING MAX(ID) IS NOT NULLзапит, хоча, хоча це і семантично не повинно бути, це може покращити приклад
Мартін Сміт

2
Чудово працює в PostgreSQL 8.4.
півночі

63
delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

Постгреси:

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid

Навіщо публікувати рішення Postgres у питанні про SQL Server?
Ланкімарт

2
@Lankymart Тому що сюди також приходять користувачі postgres. Подивіться на результат цієї відповіді.
Габріель

2
Я бачив це в деяких популярних питаннях SQL, як і тут , тут і тут . ОП отримала свою відповідь, і всі інші також отримали допомогу. Без проблем IMHO.
Габріель

44
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 

1
Я отримую це повідомлення на azure SQL DW: В даний момент пропозиція FROM не підтримується в операторі DELETE.
Аміт

40

Це видалить повторювані рядки, крім першого ряду

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

Посилання ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )


10
Для mysql він дасть помилку: Код помилки: 1093. Ви не можете вказати цільову таблицю 'Mytable' для оновлення в пункті FROM. але ця невелика зміна буде працювати для mysql: ВИДАЛИТИ З Mytable, Звідки НЕ ВИДАЄТЬСЯ (ВИБІР ІДЕНТ ВІД (ВИБІР МІН (RowID) ЯК ІД ІЗ МІТАЛЬНОЇ ГРУПИ ПО Col1, Col2, Col3) ЯК ТЕМП)
Ritesh

35

Я віддаю перевагу CTE для видалення повторюваних рядків із таблиці серверів sql

настійно рекомендую дотримуватися цієї статті :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

зберігаючи оригінал

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

без збереження оригіналу

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)

24

Для отримання повторюваних рядків:

SELECT
name, email, COUNT(*)
FROM 
users
GROUP BY
name, email
HAVING COUNT(*) > 1

Щоб видалити повторювані рядки:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      

Для користувачів MySQL зауважте, що, по-перше, це має бути DELETE FROM, по-друге, це не працюватиме, тому що ви не можете SELECTз тієї ж таблиці, з якої ви працюєте DELETE. У MySQL це вибух MySQL error 1093.
Íhor Mé

23

Швидке та брудне видалення точних дублюваних рядків (для невеликих таблиць):

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;

3
Зауважте, що питання фактично вказує неточне дублювання (ідентифікатор рядка дуето).
Денніс Джахеруддін

21

Я віддаю перевагу підзапросу \ мати count (*)> 1 рішення для внутрішнього з'єднання, тому що мені було легше читати, і це було дуже легко перетворити на оператор SELECT, щоб перевірити, що буде видалено, перш ніж запустити його.

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)

Чи не видаляє всі записи, які відображаються у внутрішньому запиті. Нам потрібно видалити лише дублікати і зберегти оригінал.
Сенді

3
Ви повертаєте лише той, який має найменший ідентифікатор, виходячи з min (id) у пункті вибору.
Джеймс Еріко

2
Відміняйте перший, другий та останній рядки запиту.
Джеймс Еріко

7
Це не очистить усі дублікати. Якщо у вас є 3 ряди, які є дублікатами, він вибере рядок лише з MIN (id) і видалить цей, залишивши два ряди, які є дублікатами.
Хлоя

2
Тим не менш, я закінчила використовувати це твердження, повторюване знову і знову, так що воно фактично прогресує замість того, щоб вимкнути час з'єднання або комп’ютер перейти у режим сну. Я змінив його, щоб MAX(id)усунути останні дублікати, і додав LIMIT 1000000до внутрішнього запиту, щоб не довелося сканувати всю таблицю. Це показало прогрес набагато швидше, ніж інші відповіді, які, здавалося б, висять годинами. Після того, як таблицю було обрізано до керованого розміру, ви можете закінчити з іншими запитами. Порада: переконайтеся, що col1 / col2 / col3 має показники для групи по.
Хлоя

17
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable

5
Обрізка не буде працювати, якщо у вас є посилання іноземних ключів на myTable.
Самер Алібхай

15

Я думав, що поділюсь своїм рішенням, оскільки воно працює за особливих обставин. У моєму випадку таблиця з повторюваними значеннями не мала стороннього ключа (оскільки значення дублювалися з іншого db).

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

PS: працюючи над подібними речами, я завжди використовую транзакцію, це не тільки забезпечує все, що виконується в цілому, але і дозволяє мені протестувати, нічого не ризикуючи. Але поза увагою, ви все одно повинні взяти резервну копію, щоб бути впевненою ...


14

Цей запит показав для мене дуже хороші показники:

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

вона видалила 1М рядків трохи більше 30 сек з таблиці 2М (50% дублікатів)


14

Використання CTE. Ідея полягає в тому, щоб приєднатися до одного або декількох стовпців, які утворюють повторюваний запис, а потім видалити те, що вам завгодно:

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;

1
Я думаю, що у вашому ПРИЄДНАННІ ви пропускаєте І
Джастін Р.

13

Ще одне просте рішення можна знайти за посиланням, яке тут вклеєно . Це легко зрозуміти і, здається, є ефективним для більшості подібних проблем. Він призначений для SQL Server, але концепція, що використовується, більш ніж прийнятна.

Ось відповідні частини зі пов’язаної сторінки:

Розглянемо ці дані:

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

Тож як можна видалити ці дублікати даних?

Спочатку вставте стовпець посвідчення в цю таблицю, використовуючи наступний код:

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

Використовуйте такий код, щоб вирішити його:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 

1
"Легко зрозуміти", "здається, є ефективним", але ні слова про те, з чого складається метод. Просто уявіть, що посилання стає недійсним, яке б використання тоді було знати, що метод був легко зрозуміти та ефективний? Будь ласка, подумайте про те, щоб додати до своєї публікації важливі частини опису методу, інакше це не відповідь.
Андрій М

Цей метод корисний для таблиць, де ще не визначено особу. Часто вам потрібно позбутися дублікатів, щоб визначити первинний ключ!
Джефф Девіс

@JeffDavis - ROW_NUMBERВерсія в цьому випадку прекрасно працює, без необхідності переходити до додавання нового стовпця до початку.
Мартін Сміт

12

Ось ще одна гарна стаття про видалення дублікатів .

У ньому обговорюється, чому це важко: " SQL заснований на реляційній алгебрі, а дублікати не можуть зустрічатися в реляційній алгебрі, оскільки дублікати не дозволені в наборі ".

Рішення таблиці темп та два приклади mysql.

В майбутньому ви збираєтеся запобігти це на рівні бази даних або з точки зору програми. Я б запропонував рівень бази даних, оскільки ваша база даних повинна відповідати за підтримку референтної цілісності, розробники просто спричинить проблеми;)


1
SQL базується на множинах. Але навіть якщо він базувався на множинах, ці два кортежі (1, а) і (2, а) різні.
Андрій

12

О, звичайно. Використовуйте таблицю темп. Якщо ви хочете отримати одне, не дуже ефективне твердження, яке "працює", ви можете:

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

В основному, для кожного рядка таблиці підвідбір знаходить верхній RowID усіх рядків, які точно схожі на розглянутий рядок. Отже, ви закінчуєте список RowID, які представляють "оригінальні" не дублюються рядки.


11

У мене була таблиця, де мені потрібно було зберегти неповторні рядки. Я не впевнений у швидкості чи ефективності.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )

7
Це передбачає, що існує максимум 1 дублікат.
Мартін Сміт

Чому ні HAVING COUNT(*) > 1?
Philipp M

11

Використовуй це

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1

10

Інший спосіб - Створити нову таблицю з тими ж полями та за допомогою унікального індексу . Потім перемістіть усі дані зі старої таблиці до нової таблиці . Автоматично ігнорувати SQL SERVER (також є варіант про те, що робити, якщо буде повторюване значення: ігнорувати, переривати чи sth) дублюючі значення. Отже, у нас однакова таблиця без повторюваних рядків. Якщо ви не хочете унікального індексу, після передачі даних ви можете його скинути .

Особливо для великих таблиць ви можете використовувати DTS (пакет SSIS для імпорту / експорту даних) для швидкого перенесення всіх даних у вашу нову унікально індексовану таблицю. На 7 мільйонів рядів потрібно лише кілька хвилин.


9

Використовуючи запит нижче, ми можемо видалити повторювані записи на основі одного стовпця або декількох стовпців. нижче запит видаляється на основі двох стовпців. назва таблиці: testingта назви стовпцівempno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)

9
  1. Створіть нову порожню таблицю з тією ж структурою

  2. Виконайте такий запит

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
  3. Потім виконайте цей запит

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1

9

Це найпростіший спосіб видалення дубліката запису

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105


Чому хтось виступає за це? Якщо у вас є більше двох однакових ідентифікаторів, НЕ БУДЕ працювати. Замість цього напишіть: видаліть з tblemp, де id не в (виберіть min (id) з групи tblemp за назвою)
crellee

7

Я б зазначив такий підхід, як він може бути корисним, і він працює на всіх SQL-серверах: Досить часто існує лише один - два дублікати, і ІД та кількість дублікатів відомі. В цьому випадку:

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0

7

З рівня програми (на жаль). Я погоджуюся, що правильний спосіб запобігти дублюванню - це на рівні бази даних за допомогою унікального індексу, але в SQL Server 2005 індекс має бути лише 900 байт, і моє поле varchar (2048) видаляє це.

Я не знаю, наскільки добре це буде, але я думаю, що ви можете написати тригер для цього, навіть якщо ви не могли зробити це безпосередньо з індексом. Щось на зразок:

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

Також варчар (2048 р.) Звучить для мене рибно (деякі речі в житті - 2048 байт, але це досить незвично); чи справді це не має бути varchar (max)?


7

Ще один спосіб зробити це: -

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 

Чим відрізняється ця відповідь від 20 серпня 2008 року? - stackoverflow.com/a/18934/692942
Lankymart

7
DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );

Привіт Teena, ви пропустили таблицю Alice ім'я T1 після видалення коментаря, інакше це призведе до виключення синтаксису.
Nagaraj M

6
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)

6

Я хочу переглянути попередній рядок, який ви збираєтеся видалити, і контролювати, який із повторюваних рядків потрібно зберегти. Дивіться http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/

with MYCTE as (
  SELECT ROW_NUMBER() OVER (
    PARTITION BY DuplicateKey1
                ,DuplicateKey2 -- optional
    ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed
  ) RN
  FROM MyTable
)
DELETE FROM MYCTE
WHERE RN > 1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.