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

时间:2010-03-25 05:02:24

标签: sql sql-server tsql sql-insert

我有以下两个表:

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

Table2
----------
ID   Name
1    Z

我需要将Table1的数据插入Table2。我可以使用以下语法:

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

但是,在我的情况下,Table2中可能存在重复的ID(在我的情况下,它只是“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语句。

10 个答案:

答案 0 :(得分:178)

使用NOT EXISTS

INSERT INTO TABLE_2
  (id, name)
SELECT t1.id,
       t1.name
  FROM TABLE_1 t1
 WHERE NOT EXISTS(SELECT id
                    FROM TABLE_2 t2
                   WHERE t2.id = t1.id)

使用NOT IN

INSERT INTO TABLE_2
  (id, name)
SELECT t1.id,
       t1.name
  FROM TABLE_1 t1
 WHERE t1.id NOT IN (SELECT id
                       FROM TABLE_2)

使用LEFT JOIN/IS NULL

INSERT INTO TABLE_2
  (id, name)
   SELECT t1.id,
          t1.name
     FROM TABLE_1 t1
LEFT JOIN TABLE_2 t2 ON t2.id = t1.id
    WHERE t2.id IS NULL

在这三个选项中,LEFT JOIN/IS NULL效率较低。请参阅this link for more details

答案 1 :(得分:30)

在MySQL中你可以这样做:

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

SQL Server有类似的东西吗?

答案 2 :(得分:6)

我遇到了类似的问题,DISTINCT关键字有效:

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

答案 3 :(得分:3)

在唯一索引as suggested by IanC here上使用ignore Duplicates是针对类似问题的解决方案,使用选项WITH IGNORE_DUP_KEY创建索引

In backward compatible syntax
, WITH IGNORE_DUP_KEY is equivalent to WITH IGNORE_DUP_KEY = ON.

参考:index_option

答案 4 :(得分:3)

从SQL Server,您可以在表上设置唯一键索引(需要唯一的列)

From sql server right click on the table design select Indexes/Keys

Select column(s) that will be not duplicate , then type Unique Key

答案 5 :(得分:2)

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

如果第二次运行它,您将获得

  

违反主键约束错误

这是代码:

Insert into Table_2
Select distinct *
from Table_1
where table_1.ID >1

答案 6 :(得分:0)

有点偏离主题,但是如果要将数据迁移到新表,并且可能的重复项位于原始表中,并且可能重复的列不是id,则为{ {1}}会:

GROUP BY

答案 7 :(得分:0)

DELETE之前的简单INSERT就足够了:

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

根据要保留的表的Table1Table2配对,将Id切换为name

答案 8 :(得分:0)

就我而言,我在源表中有重复的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

答案 9 :(得分:0)

我使用 MERGE 查询来填充一个没有重复的表。 我遇到的问题是表中的双键(代码,值), 并且存在查询非常慢 MERGE 执行得非常快(超过 X100)

examples for MERGE query