是的,你可以多次找到类似的问题,但是: 这里发布的最优雅的解决方案适用于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;
答案 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 post是NOT IN
可能会更慢的评论。但这是针对SQL服务器的,有时优雅更重要:) - 我也认为这一切都取决于良好的索引。
无论如何,通常设计不好,没有PK的桌子。您至少应该添加一个“autoinc”ID,如果这样做,您可以使用该ID而不是ROWID()
函数,这是Sybase的非标准扩展(其他人也有)。 / p>