如何避免表值函数返回的重复ID行插入@MainTable?
解决表值函数返回重复ID插入主表的问题
你的代码中NOT EXISTS失效的核心原因是:INSERT...SELECT会先一次性生成所有待插入的行集合,再批量插入。NOT EXISTS仅判断插入前@MainTable的状态,而不会在插入过程中逐行检查实时状态。当CROSS APPLY返回的结果里包含重复ID(比如ID=100同时出现在function(100)和function(200)的结果中),这些重复ID在插入前的@MainTable中都不存在,因此会被全部插入,导致重复。
要实现「保留首次出现的ID行,忽略后续重复ID」的需求,需要先对CROSS APPLY的返回结果去重,再结合NOT EXISTS判断主表已有数据。可以用窗口函数ROW_NUMBER()实现去重,确保每个ID只保留第一次出现的行:
修改后的代码:
INSERT INTO @MainTable SELECT FT.ID, FT.Name, FT.ParentID FROM ( SELECT FT.ID, FT.Name, FT.ParentID, -- 按ID分组,按@Table2的ID顺序排序,取每个ID的第一行 ROW_NUMBER() OVER (PARTITION BY FT.ID ORDER BY A.ID) AS RowNum FROM ( SELECT T2.ID FROM @Table2 T2 WHERE T2.UserID = @UserID AND ... ) A CROSS APPLY functionName(A.ID) FT ) AS FilteredFT WHERE FilteredFT.RowNum = 1 AND NOT EXISTS ( SELECT 1 FROM @MainTable MT WHERE MT.ID = FilteredFT.ID )
代码说明
ROW_NUMBER() OVER (PARTITION BY FT.ID ORDER BY A.ID):以FT.ID为分组依据,以@Table2的ID顺序(即调用函数的顺序)为排序规则,给每个ID的行分配序号。这样ID=100在function(100)中的行序号为1,在function(200)中的行序号为2,只会保留序号为1的行。- 外层的
NOT EXISTS确保去重后的行不会与@MainTable中已存在的ID重复。
这样处理后,插入的结果会完全符合你的预期:仅保留每个ID首次出现的行,同时不会插入@MainTable中已有的ID。
内容的提问来源于stack exchange,提问作者bunba
相关产品推荐
相关产品推荐

