Удалить дубликаты записей из таблицы 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' - это имя индекса.