如果没有唯一键,如何删除sybase中的重复行?

时间:2013-10-23 14:25:56

标签: sql sybase duplicate-removal sqlanywhere

是的,你可以多次找到类似的问题,但是: 这里发布的最优雅的解决方案适用于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;

5 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:1)

这很有效且很快:

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语句即可查看它的作用。

答案 2 :(得分:0)

请试试这个:

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

答案 3 :(得分:0)

这是我发现和采用的另一个有趣的一个:

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()的解决方案,我很有兴趣看到它们。

答案 4 :(得分:-1)

好的,现在我知道了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 postNOT IN可能会更慢的评论。但这是针对SQL服务器的,有时优雅更重要:) - 我也认为这一切都取决于良好的索引。

无论如何,通常设计不好,没有PK的桌子。您至少应该添加一个“autoinc”ID,如果这样做,您可以使用该ID而不是ROWID()函数,这是Sybase的非标准扩展(其他人也有)。 / p>