仅当行不存在时才插入 SQL

Posted

技术标签:

【中文标题】仅当行不存在时才插入 SQL【英文标题】:SQL Insert Only If Row is Not Present 【发布时间】:2017-02-13 20:42:26 【问题描述】:

我有以下数据表。

表_1

ID, GROUP_ID, ARTIFACT_ID, VERSION  
101, com.abc, pqra, 1.0.0  
102, com.abc, pqrb, 2.0.0  
103, com.abc, pqrc, 3.0.0  
104, com.abc, pqrd, 4.0.0 

表_2

ID, MODULE_ID, ISSUE_KEY  
11, 104, XYZ-12  
12, 104, XYZ-34

我正在使用以下命令在 Table_2 中插入值。

INSERT INTO Table_2 (MODULE_ID, ISSUE_KEY) SELECT ID, 'XYZ-56' FROM Table_1
WHERE Table_1.GROUP_ID = 'com.abc' AND Table_1.ARTIFACT_ID = 'pqrd' AND 
Table_1.VERSION = '4.0.0'  

正如您从上述查询中推断的那样,我首先尝试从 TABLE_1 中获取给定 GROUP_IDARTIFACT_IDVERSION 值的 ID,然后使用检索到的 @987654329 将数据插入 TABLE_2 @ 和 ISSUE_KEY 的值为 XYZ-56。 执行上述命令后,Table_2 将如下所示

ID, MODULE_ID, ISSUE_KEY  
11, 104, XYZ-12  
12, 104, XYZ-34
13, 104, XYZ-56

上述INSERT查询的问题是它不会检查是否已经存在具有特定值MODULE_IDISSUE_KEY的给定行。例如,如果我再次执行相同的插入查询,那么表将如下所示

ID, MODULE_ID, ISSUE_KEY  
11, 104, XYZ-12  
12, 104, XYZ-34
13, 104, XYZ-56
14, 104, XYZ-56

我希望仅将行插入到 Table_2 中,因为给定的 MODULE_IDISSUE_KEY 已经不存在任何行。 有人可以帮我修改上面的插入查询以按预期进行。

【问题讨论】:

使用不存在像这里***.com/a/41186684/2562699 【参考方案1】:

您可以使用WHERE NOT EXISTS

Insert  Into Table_2 (MODULE_ID, ISSUE_KEY)
Select  ID, 'XYZ-56'
From    Table_1 T1
Where   T1.GROUP_ID = 'com.abc'
And     T1.ARTIFACT_ID = 'pqrd'
And     T1.VERSION = '4.0.0'
And Not Exists
(
    Select  *
    From    Table_2 T2
    Where   T2.Module_Id = T1.Id
    And     T2.Issue_Key = 'XYZ-56'
);

这是使用CTELEFT JOIN 的另一种方法:

;With ToInsert As
(
    Select  ID As Module_Id, 'XYZ-56' As Issue_Key
    From    Table_1 T1
    Where   T1.GROUP_ID = 'com.abc'
    And     T1.ARTIFACT_ID = 'pqrd'
    And     T1.VERSION = '4.0.0'
)
Insert      Table_2
            (Module_Id, Issue_Key)
Select      I.Module_Id, I.Issue_Key
From        ToInsert    I
Left Join   Table_2     T2  On  T2.Module_Id = I.Module_Id
                            And T2.Issue_Key = I.Issue_Key
Where       T2.Id Is Null;

【讨论】:

【参考方案2】:

您可以使用下面的 if 块来检查记录是否存在:

IF NOT EXISTS (SELECT * FROM Table_2 WHERE ISSUE_KEY = 'XYZ-56')
BEGIN

INSERT INTO Table_2 (MODULE_ID, ISSUE_KEY) SELECT ID, 'XYZ-56' FROM Table_1
WHERE Table_1.GROUP_ID = 'com.abc' AND Table_1.ARTIFACT_ID = 'pqrd' AND 
Table_1.VERSION = '4.0.0'

END

【讨论】:

【参考方案3】:

你可以使用except:

INSERT INTO Table_2 (MODULE_ID, ISSUE_KEY) 
SELECT ID, 'XYZ-56' 
FROM Table_1
WHERE Table_1.GROUP_ID = 'com.abc' 
  AND Table_1.ARTIFACT_ID = 'pqrd' 
  AND Table_1.VERSION = '4.0.0'  

except 
select MODULE_ID, ISSUE_KEY
from Table_2

not exists():

INSERT INTO Table_2 (MODULE_ID, ISSUE_KEY) 
SELECT ID, 'XYZ-56' 
FROM Table_1
WHERE Table_1.GROUP_ID = 'com.abc' 
  AND Table_1.ARTIFACT_ID = 'pqrd' 
  AND Table_1.VERSION = '4.0.0'  
  and not exists (
    select 1
    from table_2 as i
    where i.Module_ID = table_1.ID
      and i.Issue_Key = 'XYZ-56' 
  )

或其他类似方法。

【讨论】:

虽然它可能是可取的,但使用except 也可以删除重复项。这也表明它进行了额外的、不必要的处理。 @GordonLinoff 是的,它确实删除了重复项。在检查相等性时,它还会以不同的方式处理 null 值。【参考方案4】:

您正在寻找Merge 声明。

引用文档:

根据与源表连接的结果对目标表执行插入、更新或删除操作。例如,您可以通过根据在另一个表中发现的差异在一个表中插入、更新或删除行来同步两个表。

注意:仔细阅读性能提示。

【讨论】:

以上是关于仅当行不存在时才插入 SQL的主要内容,如果未能解决你的问题,请参考以下文章

仅当行不存在时才附加到 csv

仅当行不存在时,如何将一行添加到不同子目录下的多个文本文件?

当行不存在时,“SELECT FOR UPDATE”是不是会阻止其他连接插入?

PL/SQL - 仅当记录不存在时才插入记录

仅当记录不存在时才将 SQL 插入表中[重复]

MYSQL - 仅当 LEFT JOIN 中的行不存在时才选择