Удалить дубликаты записей из таблицы SQL без первичного ключа

У меня есть таблица ниже с записями ниже

create table employee
(
 EmpId number,
 EmpName varchar2(10),
 EmpSSN varchar2(11)
);

insert into employee values(1, 'Jack', '555-55-5555');
insert into employee values (2, 'Joe', '555-56-5555');
insert into employee values (3, 'Fred', '555-57-5555');
insert into employee values (4, 'Mike', '555-58-5555');
insert into employee values (5, 'Cathy', '555-59-5555');
insert into employee values (6, 'Lisa', '555-70-5555');
insert into employee values (1, 'Jack', '555-55-5555');
insert into employee values (4, 'Mike', '555-58-5555');
insert into employee values (5, 'Cathy', '555-59-5555');
insert into employee values (6 ,'Lisa', '555-70-5555');
insert into employee values (5, 'Cathy', '555-59-5555');
insert into employee values (6, 'Lisa', '555-70-5555');

У меня нет первичного ключа в этой таблице. Но у меня уже есть вышеупомянутые записи в моей таблице. Я хочу удалить дубликаты записей, которые имеют одинаковое значение в полях EmpId и EmpSSN.

Пример: Emp id 5

Может ли кто-нибудь помочь мне создать запрос для удаления этих дубликатов

заранее спасибо

20 ответов

Решение

Добавить первичный ключ (код ниже)

Запустите правильное удаление (код ниже)

Подумайте, ПОЧЕМУ вы не хотите сохранять этот первичный ключ.


Предполагая MSSQL или совместимый:

ALTER TABLE Employee ADD EmployeeID int identity(1,1) PRIMARY KEY;

WHILE EXISTS (SELECT COUNT(*) FROM Employee GROUP BY EmpID, EmpSSN HAVING COUNT(*) > 1)
BEGIN
    DELETE FROM Employee WHERE EmployeeID IN 
    (
        SELECT MIN(EmployeeID) as [DeleteID]
        FROM Employee
        GROUP BY EmpID, EmpSSN
        HAVING COUNT(*) > 1
    )
END

Это очень просто. Я пробовал в SQL Server 2008

DELETE SUB FROM
(SELECT ROW_NUMBER() OVER (PARTITION BY EmpId, EmpName, EmpSSN ORDER BY EmpId) cnt
 FROM Employee) SUB
WHERE SUB.cnt > 1

Используйте номер строки, чтобы различать дубликаты записей. Сохраните номер первого ряда для EmpID/EmpSSN и удалите остальные:

    DELETE FROM Employee a
     WHERE ROW_NUMBER() <> ( SELECT MIN( ROW_NUMBER() )
                               FROM Employee b
                              WHERE a.EmpID  = b.EmpID
                                AND a.EmpSSN = b.EmpSSN )
With duplicates

As
(Select *, ROW_NUMBER() Over (PARTITION by EmpID,EmpSSN Order by EmpID,EmpSSN) as Duplicate From Employee)

delete From duplicates

Where Duplicate > 1 ;

Это обновит таблицу и удалит все дубликаты из таблицы!

Код

DELETE DUP 
FROM 
( 
    SELECT ROW_NUMBER() OVER (PARTITION BY Clientid ORDER BY Clientid ) AS Val 
    FROM ClientMaster 
) DUP 
WHERE DUP.Val > 1

объяснение

Используйте внутренний запрос для построения представления таблицы, которая включает в себя поле на основе Row_Number(), разделенный на эти столбцы, вы хотите быть уникальным.

Удалить из результатов этого внутреннего запроса, выбрав все, что не имеет номера строки 1; т.е. дубликаты; не оригинал.

order by предложение оконной функции row_number необходимо для правильного синтаксиса; Вы можете поставить любое имя столбца здесь. Если вы хотите изменить, какой из результатов обрабатывается как дубликат (например, сохранить самый ранний или самый последний и т. Д.), То столбцы, используемые здесь, имеют значение; т.е. вы хотите указать порядок так, чтобы запись, которую вы хотите сохранить, была первой в результате.

select distinct * into newtablename from oldtablename

Теперь newtablename не будет дубликатов записей.

Просто измените имя таблицы (newtablename), нажав F2 в проводнике объектов на сервере SQL.

Вы можете создать временную таблицу #tempemployee содержащий select distinct вашей employee Таблица. затем delete from employee, затем insert into employee select from #tempemployee,

Как сказал Джош - даже если вы знаете дубликаты, их удаление будет невозможным, поскольку вы не можете на самом деле ссылаться на конкретную запись, если она является точной копией другой записи.

ЕГО легко использовать ниже запроса

WITH Dups AS
(
  SELECT col1,col2,col3,
ROW_NUMBER() OVER(PARTITION BY col1,col2,col3 ORDER BY (SELECT 0)) AS rn
 FROM mytable
)
DELETE FROM Dups WHERE rn > 1

Если вы не хотите создавать новый первичный ключ, вы можете использовать команду TOP в SQL Server:

declare @ID int
while EXISTS(select count(*) from Employee group by EmpId having count(*)> 1)
begin
    select top 1 @ID = EmpId
    from Employee 
    group by EmpId
    having count(*) > 1

    DELETE TOP(1) FROM Employee WHERE EmpId = @ID
end

Удалить подпункт из (выберите ROW_NUMBER() OVer(Разделение по порядку empid по empid)cnt из сотрудника)sub, где sub.cnt>1

создать уникальный кластерный индекс Employee_idx
на сотрудника ( EmpId,EmpSSN)
с помощью ignore_dup_key

Вы можете удалить индекс, если он вам не нужен.

Нет IDнет rowcount() или нет temp table требуется....

WHILE 
  (
     SELECT  COUNT(*) 
     FROM TBLEMP  
     WHERE EMPNO 
            IN (SELECT empno  from tblemp group by empno having count(empno)>1)) > 1 


DELETE top(1)  
FROM TBLEMP 
WHERE EMPNO IN (SELECT empno  from tblemp group by empno having count(empno)>1)

Я не эксперт по SQL, поэтому терпите меня. Я уверен, что вы получите лучший ответ достаточно скоро. Вот как вы можете найти дубликаты записей.

select t1.empid, t1.empssn, count(*)
from employee as t1 
inner join employee as t2 on (t1.empid=t2.empid and t1.empssn = t2.empssn)
group by t1.empid, t1.empssn
having count(*) > 1

Их удаление будет более сложным, поскольку в данных нет ничего, что можно было бы использовать в операторе удаления для разграничения дубликатов. Я подозреваю, что ответ будет включать row_number() или добавление столбца идентификации.

В идентификаторе и имени таблицы есть два столбца, где имена повторяются с разными идентификаторами, поэтому вы можете использовать этот запрос: .,

DELETE FROM dbo.tbl1
WHERE id NOT IN (
     Select MIN(Id) AS namecount FROM tbl1
     GROUP BY Name
)

Наличие таблицы базы данных без первичного ключа действительно и скажет очень ПЛОХАЯ ПРАКТИКА... поэтому после добавления одной (ALTER TABLE)

Запускайте это до тех пор, пока вы не увидите больше дублированных записей (это цель HAVING COUNT)

DELETE FROM [TABLE_NAME] WHERE [Id] IN 
(
    SELECT MAX([Id])
    FROM [TABLE_NAME]
    GROUP BY [TARGET_COLUMN]
    HAVING COUNT(*) > 1
)


SELECT MAX([Id]),[TABLE_NAME], COUNT(*) AS dupeCount
FROM [TABLE_NAME]
GROUP BY [TABLE_NAME]
HAVING COUNT(*) > 1

MAX ([Id]) приведет к удалению последних записей (которые были добавлены после первого создания), если вы хотите противоположное значение, что в случае необходимости удаления первых записей и оставления последней записи, используйте MIN([Id])

Давайте мыслить нестандартно.

Я не удаляю из таблицы, я сначала создаю новую таблицу, для безопасности. лично я предпочитаю делать

      INSERT INTO new_table SELECT DISTINCT * FROM orig_table;

Теперь new_table теперь должна содержать ожидаемые данные, которые мне нужны. Я могу проверить new_table, чтобы убедиться в этом.

Тогда у меня есть 2 варианта замены orig_table

А. удалить orig_table; переименовать new_table в orig_table

B. обрезать исходную_таблицу; вставить данные из new_table в orig_table; удалить new_table ( рекомендуется : если у вас есть какой-то триггер/что-то еще, связанное с исходной таблицей orig_table)

Удалить из сотрудника, где rowid в (выберите rowid из (выберите rowid, name_count из (выберите rowid, count(emp_name) как name_count из группы сотрудников по emp_id, emp_name), где name_count>1))

select t1.* from employee t1, employee t2 where t1.empid=t2.empid and t1.empname = t2.empname and t1.salary = t2.salary
group by t1.empid, t1.empname,t1.salary having count(*) > 1
DELETE FROM 'test' 
USING 'test' , 'test' as vtable
WHERE test.id>vtable.id and test.common_column=vtable.common_column  

Используя это мы можем удалить дубликаты записей

Тест ALTER IGNORE TABLE
           ДОБАВЬТЕ УНИКАЛЬНЫЙ ИНДЕКС 'test' ('b'); 

@ здесь 'b' - это имя столбца уникальности, @ здесь 'test' - это имя индекса.

Другие вопросы по тегам