Удалить дубликаты из таблицы - PullRequest
5 голосов
/ 28 октября 2008

Тип базы данных: 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

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

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

Ответы [ 7 ]

6 голосов
/ 28 октября 2008

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

Ваша лучшая ставка выглядит примерно так:

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 голосов
/ 28 октября 2008

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

0 голосов
/ 28 октября 2008

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

Синтаксис 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 голосов
/ 28 октября 2008

Используя 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]=@counter)
                and
            (
                [f1] = (Select [f1] from #dupes where [id]=@counter)
                and
                [f2] = (Select [f2] from #dupes where [id]=@counter)
                and
                [f3] = (Select [f3] from #dupes where [id]=@counter)
            )
       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

Протестировано на MS SQL Server 2000. Не знаком с опциями Postgres, но, возможно, это приведет вас в правильном направлении.

0 голосов
/ 28 октября 2008

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

SELECT DISTINCT поле1, поле2, поле3 ИЗ таблицы1

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

0 голосов
/ 28 октября 2008

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

DELETE FROM table1
WHERE OID NOT IN (SELECT   MIN (OID)
                              FROM table1
                          GROUP BY field1, field2, field3)
0 голосов
/ 28 октября 2008

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

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

Я не уверен, требуется ли 'работа' в операторах транзакции, или нет необходимости явного BEGIN в PostgreSQL. Но концепция применима к любой СУБД.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...