2

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

5 回答 5

6

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

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
于 2014-10-21T17:17:11.860 回答
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语句即可查看它的作用。

于 2013-10-23T14:25:56.143 回答
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
于 2013-10-23T15:11:51.190 回答
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(),我很想看看他们。

于 2013-10-24T08:05:15.077 回答
-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
);

这篇给我最大启发的帖子中,有一条NOT IN可能会比较慢的评论。但这适用于 SQL 服务器,有时优雅更重要:) - 我也认为这完全取决于良好的索引。

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

于 2013-10-24T06:15:43.623 回答