在SQL Server中的INSERT INTO SELECT查询中避免重复

在SQL Server中的INSERT INTO SELECT查询中避免重复,sql,sql-server,tsql,sql-insert,Sql,Sql Server,Tsql,Sql Insert,我有以下两个表格: Table1 ---------- ID Name 1 A 2 B 3 C Table2 ---------- ID Name 1 Z 我需要将数据从表1插入表2。我可以使用以下语法: INSERT INTO Table2(Id, Name) SELECT Id, Name FROM Table1 然而,在我的例子中,重复的ID可能存在于表2中,在我的例子中,它只是1,我不想再次复制它,因为那样会引发错误 我可以这样写: IF NOT E

我有以下两个表格:

Table1
----------
ID   Name
1    A
2    B
3    C

Table2
----------
ID   Name
1    Z
我需要将数据从表1插入表2。我可以使用以下语法:

INSERT INTO Table2(Id, Name) SELECT Id, Name FROM Table1
然而,在我的例子中,重复的ID可能存在于表2中,在我的例子中,它只是1,我不想再次复制它,因为那样会引发错误

我可以这样写:

IF NOT EXISTS(SELECT 1 FROM Table2 WHERE Id=1)
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1 
ELSE
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1 WHERE Table1.Id<>1
有没有更好的方法不用IF-ELSE就可以做到这一点?基于某些条件,我希望避免使用两个INSERT INTO-SELECT语句。

使用NOT EXISTS:

不在以下位置使用:

使用左JOIN/IS为空:


在这三个选项中,左JOIN/IS NULL的效率较低。请参阅。

在MySQL中,您可以执行以下操作:

INSERT IGNORE INTO Table2(Id, Name) SELECT Id, Name FROM Table1
SQL Server是否有类似的功能?

在唯一索引上使用“忽略重复项”是我解决类似问题的解决方案,使用“忽略重复项”键选项创建索引


参考资料:

我刚刚遇到了一个类似的问题,DISTINCT关键字很神奇:

INSERT INTO Table2(Id, Name) SELECT DISTINCT Id, Name FROM Table1

在SQL Server中,可以为需要唯一的列在表上设置唯一键索引


有点离题,但如果要将数据迁移到新表,并且可能的重复项位于原始表中,并且可能重复的列不是id,则GROUP BY将执行以下操作:


我最近也面临同样的问题。。。 以下是在2017年MS SQL server中对我起作用的内容。。。 主键应该设置在表2中的ID上。。。 当然,两个表之间的列和列属性应该相同。这将在您第一次运行下面的脚本时起作用。表1中的重复ID将不会插入

如果你第二次运行它,你会得到一个

违反主键约束错误

代码如下:

Insert into Table_2
Select distinct *
from Table_1
where table_1.ID >1
在插入之前进行简单的删除即可:

DELETE FROM Table2 WHERE Id = (SELECT Id FROM Table1)
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1

根据要保留的表的Id和名称对,将表1切换到表2。

在我的例子中,源表中有重复的Id,因此所有建议都无效。我不在乎性能,只做过一次。 为了解决这个问题,我用光标一个接一个地记录,以忽略重复的记录

下面是代码示例:

DECLARE @c1 AS VARCHAR(12);
DECLARE @c2 AS VARCHAR(250);
DECLARE @c3 AS VARCHAR(250);


DECLARE MY_cursor CURSOR STATIC FOR
Select
c1,
c2,
c3
from T2
where ....;

OPEN MY_cursor
FETCH NEXT FROM MY_cursor INTO @c1, @c2, @c3

WHILE @@FETCH_STATUS = 0
BEGIN
    if (select count(1) 
        from T1
        where a1 = @c1
        and a2 = @c2
        ) = 0 
            INSERT INTO T1
            values (@c1, @c2, @c3)

    FETCH NEXT FROM MY_cursor INTO @c1, @c2, @c3
END
CLOSE MY_cursor
DEALLOCATE MY_cursor

我使用了一个合并查询来填充一个没有重复的表。 我遇到的问题是表中的一个双键代码,值, 而且exists查询非常慢 合并的执行速度比X100快


只是澄清一下不存在的版本,你需要一个预扣锁提示,否则没有锁,因为没有要锁的行!所以另一个线程可以在你下面插入行。很有趣,因为我一直认为加入比子选择更快。也许这只适用于直接连接,而不适用于左连接。Duncan,当它们是相关子查询时,连接通常比子选择更快。如果在选择列表中有子查询,则联接通常会更快。NOT EXISTS对于复合主键特别有用,NOT in不起作用then@OMGPonies-有关更多详细信息的链接似乎已失效。你还有其他可能有用的吗?+1可以教我这方面的知识。非常好的语法。绝对比我用的短而且好。不幸的是,Sql server没有这个功能。这不完全正确。创建唯一索引时,可以将其设置为忽略重复项,在这种情况下,SQL Server将忽略任何添加重复项的尝试。而SQL Server仍然无法。。。可怜。所以SQL Server仍然不能?而且仍然不能。除非我完全误解了你的意思,如果你插入的集合中有重复项,这将起作用。但是,如果要从中插入的集合可能是insert into表中已存在的数据的重复项,则不会有帮助。请不要这样做。你基本上是说我所有的数据都是毫无价值的,让我们插入这些新数据吧@如果出于某种原因,表2不应该在插入后被删除,那么使用其他方法,但这是一种完全有效的方法来实现OP所要求的。有效,但肯定较慢,并且在没有事务的情况下可能会损坏。如果你走这条路,就在一个事务中进行包装。它不会响应INSERT INGORE INTO的替代方法。
INSERT INTO Table2(Id, Name) SELECT DISTINCT Id, Name FROM Table1
INSERT INTO TABLE_2
(name)
  SELECT t1.name
  FROM TABLE_1 t1
  GROUP BY t1.name
Insert into Table_2
Select distinct *
from Table_1
where table_1.ID >1
DELETE FROM Table2 WHERE Id = (SELECT Id FROM Table1)
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1
DECLARE @c1 AS VARCHAR(12);
DECLARE @c2 AS VARCHAR(250);
DECLARE @c3 AS VARCHAR(250);


DECLARE MY_cursor CURSOR STATIC FOR
Select
c1,
c2,
c3
from T2
where ....;

OPEN MY_cursor
FETCH NEXT FROM MY_cursor INTO @c1, @c2, @c3

WHILE @@FETCH_STATUS = 0
BEGIN
    if (select count(1) 
        from T1
        where a1 = @c1
        and a2 = @c2
        ) = 0 
            INSERT INTO T1
            values (@c1, @c2, @c3)

    FETCH NEXT FROM MY_cursor INTO @c1, @c2, @c3
END
CLOSE MY_cursor
DEALLOCATE MY_cursor