如何避免在 SQL Server 中重复插入动态值

Posted

技术标签:

【中文标题】如何避免在 SQL Server 中重复插入动态值【英文标题】:How to avoid duplicate insert of dynamic values in SQL server 【发布时间】:2014-05-09 18:52:16 【问题描述】:

我想编写一个查询来插入动态值,如果它们已经存在或不存在。到目前为止,我已经尝试过了。

INSERT MTB_AML..tb_aml_codes (aml_code, aml_desc)

    SELECT 'NRA', 'Non-Resident Alien'
    UNION
    SELECT 'DOM', 'Resident Alien'
    FROM MTB_AML..tb_aml_codes t1
    WHERE t1.aml_code NOT IN (SELECT t2.aml_code from MTB_AML..tb_aml_codes t2)

但这只会返回上层选择(表中已经存在)。我做错了什么?

【问题讨论】:

有什么特殊原因需要使用 UNION 吗? @OtávioDécio 我还能如何插入动态值?我没有将它们存储在任何可以使用列名的表中。 您是否假设WHERE 应用于UNION 的结果,而不仅仅是第二个select 语句? @hatchet 即使我单独申请 where 条件,也没有解决目的。我认为我无法通过使用 INSERT 到 SELECT... 来控制非重复信息的插入以获取硬编码值。 【参考方案1】:

我认为您遇到的问题是,在您的版本中,WHERE 子句仅适用于 UNION 子句中的最后一个 Select

获取你想要的记录

 SELECT 'NRA' AS aml_code, 'Non-Resident Alien' AS aml_desc
    UNION 
 SELECT 'DOM' AS aml_code, 'Resident Alien' AS aml_desc

然后将它们包装为子查询(在示例中别名为 [src]),然后您可以检查哪些在目标表中没有匹配的键(别名为 [dst])

INSERT MTB_AML..tb_aml_codes (aml_code, aml_desc)
SELECT src.aml_code, src.aml_desc
(
    SELECT 'NRA' AS aml_code, 'Non-Resident Alien' AS aml_desc
    UNION 
    SELECT 'DOM' AS aml_code, 'Resident Alien' AS aml_desc
) src
WHERE src.aml_code NOT IN (SELECT dst.aml_code from MTB_AML..tb_aml_codes dst)

我个人会用这样的左连接来做,但这取决于你

  INSERT MTB_AML..tb_aml_codes (aml_code, aml_desc)
SELECT src.aml_code, src.aml_desc
FROM
(
    SELECT 'NRA' AS aml_code, 'Non-Resident Alien' AS aml_desc
    UNION 
    SELECT 'DOM' AS aml_code, 'Resident Alien' AS aml_desc
) src
LEFT JOIN MTB_AML..tb_aml_codes dst
ON dst.aml_code = src.aml_code
WHERE dst.aml_code IS NULL

两者都可以,但如果您必须匹配多列键,则需要使用 join 方法

【讨论】:

非常感谢!这就是我需要的。你是男人!【参考方案2】:

您正在对结果集的值进行硬编码,用引号引起来表示文字值,您必须需要 COLUMN 名称。

SELECT 'DOM', 'Resident Alien'

您需要这样的 SELECT:

SELECT T1.ColName, T1.AndAnotherColName
....

【讨论】:

谢谢,但这就是重点。只有当我知道它不存在时,我才必须在表中插入一个硬编码值。我不确定是否/如何做到这一点。 你需要展示数据示例,你的问题写得不好。【参考方案3】:

您正在插入与表MTB_AML..tb_aml_codes 无关的静态数据。所以你的插入查询可以简化如下

INSERT MTB_AML..tb_aml_codes (aml_code, aml_desc)
VALUES ('NRA', 'Non-Resident Alien'),('DOM', 'Resident Alien')

编辑:

然后您需要检查这些值是否存在并相应地进行插入,如下所示

IF NOT EXISTS 
(select 1 from MTB_AML..tb_aml_codes where aml_code in('NRA','DOM') 
and aml_desc in ('Non-Resident Alien','Resident Alien'))
BEGIN
INSERT INTO MTB_AML..tb_aml_codes (aml_code, aml_desc)
VALUES ('NRA', 'Non-Resident Alien'),('DOM', 'Resident Alien')
END

【讨论】:

感谢 Rahul,但我如何确保我没有插入重复记录?【参考方案4】:

我认为MERGE 语句可以满足您的需求。它简洁地完成了你想做的事情。

MERGE MTB_AML..tb_aml_codes AS dest
USING (
    -- place here whatever you want to insert if not already present
    -- I'm using something like what you have in your question since 
    -- that's your example
    SELECT 'NRA', 'Non-Resident Alien'
    UNION
    SELECT 'DOM', 'Resident Alien'
) AS src
ON dest.aml_code = src.aml_code
WHEN NOT MATCHED BY TARGET THEN
    INSERT (aml_code, aml_desc)
    VALUES (src.aml_code, src.aml_desc)
;

【讨论】:

非常感谢@hatchet!

以上是关于如何避免在 SQL Server 中重复插入动态值的主要内容,如果未能解决你的问题,请参考以下文章

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

如何避免两次编写 SQL Server 查询以避免重复?

在主键列(表)中插入重复值时在 SQL Server 中返回哪个错误代码

在表值函数中使用 SQL Server 2008 中的动态 SQL 语句 [重复]

如何将插入的输出值分配给 sql server 中的变量? [复制]

SQL Server插入空实例[重复]