当前位置: 首页 > 面试题库 >

使用T-SQL Merge语句时如何避免插入重复记录

葛炜
2023-03-14
问题内容

我试图使用T-SQL的MERGE语句插入许多记录,但是当源表中有重复的记录时,我的查询无法插入。失败原因是:

  1. 目标表有一个基于两列的主键
  2. 源表可能包含重复记录,这些记录违反了目标表的主键约束(引发了“违反主键约束”)

我正在寻找一种方法来更改我的MERGE语句,以便它要么忽略源表中的重复记录,并且/或者将尝试/捕获INSERT语句以捕获可能发生的异常(即,所有其他INSERT语句都将运行,而无论可能会出现一些坏蛋)-或者,也许有更好的方法来解决此问题?

这是我要解释的查询示例。以下示例将向临时表中添加100k条记录,然后尝试将这些记录插入目标表中-

编辑
在我的原始帖子中,我仅在示例表中包括两个字段,这些字段让SO朋友提供了DISTINCT解决方案,以避免在MERGE语句中出现重复。我应该提到,在我的实际问题中,表有15个字段,而在这15个字段中,两个字段是集群主键。因此DISTINCT关键字不起作用,因为我需要选择所有15个字段,并忽略基于其中两个字段的重复项。

我更新了下面的查询,以包含更多字段col4。我需要在合并中包含col4,但只需要确保col2和col3是唯一的即可。

-- Create the source table
CREATE TABLE #tmp (
col2 datetime NOT NULL,
col3 int NOT NULL,
col4 int
)
GO

-- Add a bunch of test data to the source table
-- For testing purposes, allow duplicate records to be added to this table
DECLARE @loopCount int = 100000
DECLARE @loopCounter int = 0
DECLARE @randDateOffset int
DECLARE @col2 datetime
DECLARE @col3 int
DECLARE @col4 int

WHILE (@loopCounter) < @loopCount
BEGIN
    SET @randDateOffset = RAND() * 100000
    SET @col2 = DATEADD(MI,@randDateOffset,GETDATE())
    SET @col3 = RAND() * 1000
    SET @col4 = RAND() * 10
    INSERT INTO #tmp
    (col2,col3,col4)
    VALUES
    (@col2,@col3,@col4);

    SET @loopCounter = @loopCounter + 1
END

-- Insert the source data into the target table
-- How do we make sure we don't attempt to INSERT a duplicate record? Or how can we 
-- catch exceptions? Or?
MERGE INTO dbo.tbl1 AS tbl
    USING (SELECT * FROM #tmp) AS src
    ON (tbl.col2 = src.col2 AND tbl.col3 = src.col3)
    WHEN NOT MATCHED THEN 
        INSERT (col2,col3,col4)
        VALUES (src.col2,src.col3,src.col4);
GO

问题答案:

解决了您的新规范。只插入最高的col4值:这次我使用group by来防止重复的行。

MERGE INTO dbo.tbl1 AS tbl 
USING (SELECT col2,col3, max(col4) col4 FROM #tmp group by col2,col3) AS src 
ON (tbl.col2 = src.col2 AND tbl.col3 = src.col3) 
WHEN NOT MATCHED THEN  
    INSERT (col2,col3,col4) 
    VALUES (src.col2,src.col3,src.col4);


 类似资料:
  • 如何避免在PHP MYSQLi中插入重复记录?这是我的剧本:

  • 我有一个简单的项目,该项目将个人信息提供给数据库(sqlite),现在我想避免插入重复值(按名称),我不能做什么?谢谢你们

  • 我想编写一个存储过程来将数据插入到表中,并检查是否已经存在相同的数据? 如果是,则异常抛出为已经存在。但我不知道应该在哪里添加异常。请帮忙。

  • 我有一个非常简单的表,有3列,我需要一个尽可能轻量级的查询,只有当列有新值时才能插入。 如何编写sql查询来实现这一点?我在网站上已经看到了一些例子,但它们都被我无法理解的更复杂的查询(一些涉及子查询)所混淆。 似乎有不同的方法来做这件事,我需要找到最轻量级的一个,这样我就可以在循环中重复它,一次插入多个标签,而不会给服务器带来太大的压力。

  • 我希望我的 print 语句在循环之外,这样语句就不会一遍又一遍地打印相同的内容。下面的 for 循环只是将一个数组中的数字与另一个数组进行对比,以找出找到多少个匹配项。定义上面的变量并打印下面的语句会导致“变量未初始化错误”,这是可以理解的。

  • 问题内容: 我刚刚实现了Winston Logging,它可以按预期工作,但是遇到了一些我找不到答案的问题。 据我所知,winston的工作方式是设置的日志级别,以及使用优先级以下的任何东西,例如出错时,它还将包括信息日志等。是否有一种创建特定日志级别的方法可以称之为HTTP还是db,我只将http或db事件记录到日志中,而它们并没有出现在合并的文件或控制台中? 问题答案: 更好的解决方案是使用具