2008-10-28 2 views
5

Тип базы данных - PostGres 8.3.Удалить дубликат из таблицы

Если бы я писал:

SELECT field1, field2, field3, count(*) 
FROM table1 
GROUP BY field1, field2, field3 having count(*) > 1; 

У меня есть несколько строк, которые имеют счетчик над 1. Как я могу вынуть дубликат (я все еще хочу 1 строку для каждого из них вместо +1 строки. .. Я не хочу, чтобы удалить их все)

. Пример:

1-2-3 
1-2-3 
1-2-3 
2-3-4 
4-5-6 

должны стать:

1-2-3 
2-3-4 
4-5-6 

Единственный ответ, который я нашел, - there, но мне интересно, смогу ли я сделать это без колонки hash.

Предупреждение не имеют ПК с уникальным номером, так что я не могу использовать технику мин (...). PK - это 3 поля.

+0

Я не уверен, правильно ли я это понимаю. Вы говорите: «PK - это 3 поля» - тогда как получилось, что у вас есть дубликаты в таблице, как несколько записей 1-2-3. Поправьте меня, если я ошибаюсь. – 2008-10-28 15:02:00

+0

PK был в трех полях, нам пришлось удалить их для слияния (длинный рассказ), теперь нам нужно вернуть его обратно. У нас есть несколько дубликатов, которые мы хотели бы снять. – 2008-10-28 15:10:31

ответ

6

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

Лучше что-то вроде этого:

SELECT field1, field2, field3, count(*) 
INTO temp_table1 
FROM table1 
GROUP BY field1, field2, field3 having count(*) > 1 

DELETE T1 
FROM table1 T1 
INNER JOIN (SELECT field1, field2, field3 
     FROM table1 
     GROUP BY field1, field2, field3 having count(*) > 1) SQ ON 
      SQ.field1 = T1.field1 AND 
      SQ.field2 = T1.field2 AND 
      SQ.field3 = T1.field3 

INSERT INTO table1 (field1, field2, field3) 
SELECT field1, field2, field3 
FROM temp_table1 

DROP TABLE temp_table1 
+0

В настоящее время я пытаюсь ваше предложение. +1 – 2008-10-28 15:25:09

+0

Это работает thx, я изменил немного вещей, таких как DELETE T1, не работает, мне пришлось поставить T1 после таблицы FROM1 как T1. Мало таких вещей. Но решение было быстрым и успешным. – 2008-10-28 16:33:14

0

Один из возможных ответов:

CREATE <temporary table> (<correct structure for table being cleaned>); 
BEGIN WORK; -- if needed 
INSERT INTO <temporary table> SELECT DISTINCT * FROM <source table>; 
DELETE FROM <source table> 
INSERT INTO <source table> SELECT * FROM <temporary table>; 
COMMIT WORK; -- needed 
DROP <temporary table>; 

Я не уверен, нужен ли «работа» на заявления по сделке, не является ли явное НАЧАТЬ необходимо в PostgreSQL. Но концепция применима к любой СУБД.

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

0

Это будет использовать OID идентификатор объекта (если таблица была создана с ним):

DELETE FROM table1 
WHERE OID NOT IN (SELECT MIN (OID) 
           FROM table1 
          GROUP BY field1, field2, field3) 
0

Ну я неправильно что-то, но я скажем:

SELECT DISTINCT field1, field2, field3 FROM table1

Слишком легко быть хорошим? ^^

0

Использование TSQL, понятия не имею, если Postgres не поддерживает временные таблицы, но вы можете выбрать в временную таблицу, а затем перебрать и удалить и вставить результаты обратно в исходное

-- **Disclaimer** using TSQL 
-- You could select your records into a temp table with a pk 
Create Table #dupes 
([id] int not null identity(1,1), f1 int, f2 int, f3 int) 

Insert Into #dupes (f1,f2,f3) values (1,2,3) 
Insert Into #dupes (f1,f2,f3) values (1,2,3) 
Insert Into #dupes (f1,f2,f3) values (1,2,3) 
Insert Into #dupes (f1,f2,f3) values (2,3,4) 
Insert Into #dupes (f1,f2,f3) values (4,5,6) 
Insert Into #dupes (f1,f2,f3) values (4,5,6) 
Insert Into #dupes (f1,f2,f3) values (4,5,6) 
Insert Into #dupes (f1,f2,f3) values (7,8,9) 

Select f1,f2,f3 From #dupes 

Declare @rowCount int 
Declare @counter int 
Set @counter = 1 
Set @rowCount = (Select Count([id]) from #dupes) 

while (@counter < @rowCount + 1) 
    Begin 
     Delete From #dupes 
     Where [Id] <> 
      (Select [id] From #dupes where [id][email protected]) 
       and 
      (
       [f1] = (Select [f1] from #dupes where [id][email protected]) 
       and 
       [f2] = (Select [f2] from #dupes where [id][email protected]) 
       and 
       [f3] = (Select [f3] from #dupes where [id][email protected]) 
      ) 
     Set @counter = @counter + 1 
    End 

Select f1,f2,f3 From #dupes -- You could take these results and pump them back into --your original table 

Drop Table #dupes 

Испытано это на МС SQL Server 2000. Не знакомы с параметрами Postgres, но, возможно, это приведет вас в правильном направлении.

0

Это самый простой метод, который я нашел:

Postgre SQL Синтаксис:

CREATE TABLE tmp AS SELECT distinct * FROM table1 
truncate table table1 
insert into table1 select * from tmp 
drop table tmp 

T-SQL Синтаксис:

select distinct * into #tmp from table1 
truncate table table1 
insert into table1 select * from #tmp 
drop table #tmp 
0

Хороший Answer для этой проблемы, но для SQL Server. Он использует ROWCOUNT, который предлагает SQL Server, для хорошего эффекта. Я никогда не использовал PostgreSQL и, следовательно, не знаю эквивалента ROWCOUNT в PostgreSQL.

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