如何避免在 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 2008 中的动态 SQL 语句 [重复]