【问题标题】:How to delete duplicate rows in sybase, when you have no unique key?当您没有唯一键时,如何删除sybase中的重复行?
【发布时间】:2015-12-24 06:52:53
【问题描述】:

是的,您可以多次找到类似的问题,但是: 此处发布的最优雅的解决方案适用于 SQL Server,但不适用于 Sybase(在我的情况下为 Sybase Anywhere 11)。我什至发现一些与 Sybase 相关的问题被标记为 SQL Server 问题的重复,这没有帮助。

我喜欢但不起作用的解决方案的一个示例是 WITH ... DELETE ... 构造。

我找到了使用游标或 while 循环的可行解决方案,但我希望不使用循环也是可能的。

我希望有一个漂亮、简单和快速的查询,只删除一个完全相同的重复项。

这里有一个用于测试的小框架:

IF OBJECT_ID( 'tempdb..#TestTable' ) IS NOT NULL
  DROP TABLE #TestTable;

CREATE TABLE #TestTable (Column1 varchar(1), Column2 int);

INSERT INTO #TestTable VALUES ('A', 1);
INSERT INTO #TestTable VALUES ('A', 1); -- duplicate
INSERT INTO #TestTable VALUES ('A', 1); -- duplicate
INSERT INTO #TestTable VALUES ('A', 2);
INSERT INTO #TestTable VALUES ('B', 1);
INSERT INTO #TestTable VALUES ('B', 2);
INSERT INTO #TestTable VALUES ('B', 2); -- duplicate
INSERT INTO #TestTable VALUES ('C', 1);
INSERT INTO #TestTable VALUES ('C', 2);

SELECT * FROM #TestTable ORDER BY Column1,Column2;

DELETE <your solution here>

SELECT * FROM #TestTable ORDER BY Column1,Column2;

【问题讨论】:

  • 嗯。 6200 次观看,但没有人发现我的任何答案有用?

标签: sql sybase duplicate-removal sqlanywhere


【解决方案1】:

如果所有字段都相同,您可以这样做:

select distinct * 
into #temp_table
from table_with_duplicates 

delete table_with_duplicates 

insert into table_with_duplicates select * from #temp_table

如果所有字段都不相同,例如,如果您的 id 不同,那么您需要在 select 语句中列出所有字段,并在 id 中硬编码一个值以使其相同,如果那是你不关心的领域。 例如:

insert #temp_table field1, field2, id select (field1, field2, 999)
from table_with_duplicates

【讨论】:

  • 如果我有数百万条记录但只有几个重复项怎么办?这是一个简单易记的解决方案,如果您曾经手动需要删除重复项。但它可能会慢得多,需要一个临时表,并且不完全是所要求的。此外,标题已经说明没有 ID(主键) - 如果您有 ID,无论如何您都可以使用许多其他需要主键的解决方案。
  • 缺少一个 select 和一些 ; :)
【解决方案2】:

这运行良好且快速:

DELETE FROM #TestTable
WHERE ROWID(#TestTable) IN (
  SELECT rowid FROM (
    SELECT ROWID(#TestTable) rowid, 
      ROW_NUMBER() OVER(PARTITION BY Column1,Column2 ORDER BY Column1,Column2) rownum
    FROM #TestTable
  ) sub
  WHERE rownum > 1
);

如果你不知道OVER(PARTITION BY ...),只需执行内部SELECT 语句,看看它做了什么。

【讨论】:

    【解决方案3】:

    这是我发现并采用的另一个有趣的方法:

    DELETE FROM #TestTable dupes
    FROM #TestTable dupes, #TestTable fullTable
    WHERE dupes.Column1 = fullTable.Column1
      AND dupes.Column2 = fullTable.Column2
      AND ROWID(dupes) > ROWID(fullTable);
    

    或者,如果您更喜欢显式连接(我愿意):

    DELETE FROM #TestTable dupes
    FROM #TestTable dupes
    INNER JOIN #TestTable fullTable
      ON dupes.Column1 = fullTable.Column1
      AND dupes.Column2 = fullTable.Column2
      AND ROWID(dupes) > ROWID(fullTable);
    

    或缩写形式(“自然”连接自动包含相同的列名):

    DELETE FROM #TestTable dupes
    FROM #TestTable dupes
    NATURAL JOIN #TestTable fullTable
      ON ROWID(dupes) > ROWID(fullTable);
    

    ...如果有人找到不需要ROWID() 的解决方案,我很想看看他们。

    【讨论】:

    • 是的,用“大于”加入行 ID 非常酷,并且非常有效地让同事感到惊讶 ;-) - 但是当你考虑这真正的作用时......我觉得自己像个虐待狂db 拷问器...或者优化器可以 那么 聪明并且只是嘲笑我吗?
    【解决方案4】:

    请试试这个:

    create clustered index i1 on table table_name(column_name) with ignore_dup_row
    

    create table #test(id int,name char(9))
    insert into #test values(1,"A")
    insert into #test values(1,"A")
    create clustered index i1 on #test(id) with ignore_dup_row
    select * from #test
    

    【讨论】:

    • 谢谢,了解 Sybase 选项 ignore_dup_row 和 allow_dup_row 非常有趣。但它似乎不适用于我的 Sybase 版本:创建索引时没有错误,但该选项似乎被忽略并且选择返回两行。
    • 看起来它只对 Adaptive Server Enterprise (Sybase ASE) 有效——我只是想知道为什么它没有给出任何错误。
    【解决方案5】:

    好的,现在我知道了ROWID() 函数,可以轻松采用带有主键(PK)的表的解决方案。这首先选择所有要保留的行,然后删除剩余的行:

    DELETE FROM #TestTable
    FROM #TestTable
    LEFT OUTER JOIN (
      SELECT MIN(ROWID(#TestTable)) rowid
      FROM #TestTable
      GROUP BY Column1, Column2
    ) AS KeepRows ON ROWID(#TestTable) = KeepRows.rowid
    WHERE KeepRows.rowid IS NULL;
    

    ...或者这个较短的变体怎么样?我喜欢!

    DELETE FROM #TestTable
    WHERE ROWID(#TestTable) NOT IN (
      SELECT MIN(ROWID(#TestTable))
      FROM #TestTable
      GROUP BY Column1, Column2
    );
    

    this post 中,最让我感动的是一条评论,NOT IN 可能会更慢。但这是针对 SQL 服务器的,有时优雅更重要 :) - 我也认为这完全取决于良好的索引。

    不管怎样,没有PK的桌子通常是糟糕的设计。您至少应该添加一个“autoinc”ID,如果这样做,您可以使用该 ID 代替 ROWID() 函数,这是 Sybase 的非标准扩展(其他一些也有)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-07
      • 2015-01-02
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多