2009-06-12 5 views
44

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

Ex: Emp ID 5

Может ли один помочь мне в кадр запроса, чтобы удалить эти дубликаты записей

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

+0

Вы можете * ДОБАВИТЬ * первичный ключ? Какая система баз данных или вы используете? Oracle? Пожалуйста, укажите это в своем вопросе! –

+2

Что делать, если у него одинаковые EmpID и EmpSSn, но разные имена? – cjk

+0

его SQL-сервер 2005 – Shyju

ответ

51

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

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

Подумайте, почему вы woudln't хотите сохранить этот первичный ключ.


Предполагая, что 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 
+7

+1: процитировать некоторых богов SQL: «если у него нет первичного ключа, это не таблица» –

+2

+1 Первичный ключ идентифицирует строку. Нет PK = нет смысла. @marc_s: кластерный индекс отличает таблицу от кучи. Нет PK просто означает отсутствие целостности данных. – gbn

+0

@gbn: даже куча считается таблицей :-) Эта цитата была больше по строкам: если вы не указали первичный ключ, таблица действительно не имеет большой пользы (кроме случаев с краями например, объемные импортные/временные таблицы и т. д.) –

6

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

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

+2

Только трюк есть если имена разные, но совпадение ID/SSN. Вы должны как-то выбрать один, потому что разные не помогут. – Josh

+1

+1 это самое простое и портативное решение. OP не указывает, какую марку базы данных он использует. –

+0

@Josh: из примера OP, похоже, это не проблема. Дублированные строки одинаковы во всех столбцах. –

0

Я не эксперт по 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() или добавление столбца идентификации.

22

Используйте номер строки, чтобы различать дублирующихся записей. Держите первый номер строки для 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) 
+3

+1 Хорошее решение, чтобы избежать структурных изменений. –

+0

Будет ли это работать на Oracle? У меня была эта проблема http://stackoverflow.com/questions/34948301/oracle-why-i-cannot-rely-on-rownum-in-a-delete-clause –

-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 
+0

На какой вопрос она отвечает? –

2

Если вы не хотите, чтобы создать новый первичный ключ, который вы можете использовать верхнюю команду в 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 
+0

thanx ................. –

0
create unique clustered index Employee_idx 
on Employee (EmpId,EmpSSN) 
with ignore_dup_key

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

-3
ALTER IGNORE TABLE test 
      ADD UNIQUE INDEX 'test' ('b'); 

@ здесь «Ь» является имя столбца уникальности, @ здесь «тест» является имя индекса.

+1

Не удаленно синтаксис SQL Server. –

-2
DELETE FROM 'test' 
USING 'test' , 'test' as vtable 
WHERE test.id>vtable.id and test.common_column=vtable.common_column 

С помощью этого можно удалить повторяющиеся записи

69

Это очень просто. Я пытался в 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 
+2

+1 Также отлично работает в 2005 году –

+2

Это хорошо работает, когда у вас много столбцов для группировки, и он аккуратно обрабатывает NULL! = NULL при сравнении двух столбцов. Вам не нужно перечислять каждый столбец дважды, как некоторые другие ответы («a.col = b.col»), и, что еще более важно, вам не нужно проверять »((a.col = b .col) ИЛИ (a.col IS NULL AND b.col IS NULL)) "в столбцах NULL. –

+4

Этот ответ на самом деле решает проблему без структурных изменений. Работает отлично. – SDeezy

9
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 ; 

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

6
select distinct * into newtablename from oldtablename 

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

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

0

нет 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) 
0

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

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

Имея таблицу базы данных без первичного ключа действительно и будет говорить очень плохая практика ... поэтому после добавления одного (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])

1

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

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 
3

код

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; т.е. дубликаты; а не оригинал.

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

+0

Добро пожаловать в переполнение стека! Кодовые ответы не очень полезны сами по себе. Это поможет, если вы можете добавить некоторые детали, объясняющие, как/почему он отвечает на вопрос. – SiHa

 Смежные вопросы

  • Нет связанных вопросов^_^