【问题标题】:Remove duplicate from a table从表中删除重复项
【发布时间】:2010-09-19 14:30:00
【问题描述】:

数据库类型为 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,但我想知道是否可以不使用哈希列。

警告 我没有唯一编号的 PK,所以我不能使用 min(...) 的技术。 PK 是 3 个字段。

【问题讨论】:

  • 我不确定我是否理解正确。你说“PK 是 3 个字段”——那么你怎么会在表中有重复项,比如多个 1-2-3 记录。如果我错了,请纠正我。
  • PK 在 3 个字段中,我们必须删除它们以进行合并(长话短说),现在我们需要将其放回原处。我们有一些复制品想要起飞。

标签: sql postgresql


【解决方案1】:

使用 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 的选项,但也许这会引导您朝着正确的方向前进。

【讨论】:

    【解决方案2】:

    一个很好的Answer 解决这个问题,但对于 SQL Server。它使用 SQL Server 提供的 ROWCOUNT,效果很好。我从未使用过 PostgreSQL,因此不知道 PostgreSQL 中的 ROWCOUNT 等价物。

    【讨论】:

      【解决方案3】:

      这是所有表都应具有主键的众多原因之一(不一定是 ID 号或 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
      

      【讨论】:

      • 我目前正在尝试您的建议。 +1
      • 它可以工作,我已经修改了一些东西,比如 DELETE T1 不起作用,我不得不将 T1 放在 FROM table1 之后作为 T1。很少有这样的事情。但这个解决方案在这里很快而且很成功。
      • 我很高兴它对你有用。感谢您指出我忽略了 T1 别名。我已经在脚本中更正了它。
      【解决方案4】:

      这是我发现的最简单的方法:

      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
      

      【讨论】:

        【解决方案5】:

        好吧,我应该误解了一些东西,但我会说:

        SELECT DISTINCT field1, field2, field3 FROM table1

        太容易成为好人? ^^

        【讨论】:

        • 我认为 Daok 想要删除除一个重复条目之外的所有条目。
        【解决方案6】:

        这将使用 OID 对象 ID(如果表是用它创建的):

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

        【讨论】:

          【解决方案7】:

          一个可能的答案是:

          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 中是否需要显式 BEGIN。但这个概念适用于任何 DBMS。

          唯一需要注意的是引用约束,尤其是触发的删除操作。如果这些存在,这可能证明不太令人满意。

          【讨论】:

            猜你喜欢
            • 2014-09-30
            • 2021-04-02
            • 2016-01-28
            • 2011-01-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多