无主键/外键的表如何仅插入新记录?TSQL可选方案探讨
嘿,我完全懂你的困扰——没有主键的话,确实没法像示例里那样用单一列做匹配锚点,但TSQL里有不少适合这种场景的思路,我给你拆解几个方向,你可以根据自己的表大小和需求来探索:
用所有列组合做匹配判断
既然两张表结构完全一致,那判断一条记录是否重复的核心就是「所有列的值都完全相同」。你可以把原来的WHERE t2.id = t1.id替换成所有列的相等判断,比如t2.col1 = t1.col1 AND t2.col2 = t1.col2 AND ...。虽然列多的话写起来有点繁琐,但逻辑非常直观,适合列数不算特别多或者你能快速生成条件的场景。如果列实在太多,也可以研究下动态SQL自动生成这个匹配条件,不过这属于进阶一点的操作了。用HASHBYTES生成行级唯一标识
你可以把每行的所有列值合并成一个字符串,再用HASHBYTES函数生成一个哈希值,用这个哈希值来判断记录是否重复。比如对每行计算HASHBYTES('SHA2_256', CONCAT(ISNULL(col1, ''), ISNULL(col2, ''), ...))(用ISNULL是为了处理NULL值,避免CONCAT直接返回NULL),然后比较源表和目标表的哈希值是否一致。这个方法比写一堆列等式简洁很多,尤其适合列数多的情况。试试MERGE语句
TSQL的MERGE是专门用来处理「合并源表到目标表」场景的语句,比单独的INSERT更灵活。你可以定义规则:当源表的记录在目标表中不存在时就执行插入,判断「不存在」的条件同样可以用上面说的「全列匹配」或者「哈希值匹配」。MERGE的好处是把判断和插入逻辑整合在一个语句里,可读性更强。用UNION直接生成去重后的结果
如果你的需求是直接得到合并后的去重表,而不是增量追加,那可以用SELECT * FROM TableA UNION SELECT * FROM TableB——UNION关键字本身会自动去除重复记录(注意是UNION不是UNION ALL,后者不会去重)。如果要把结果插入主表,就是INSERT INTO MainTable SELECT * FROM TableA UNION SELECT * FROM TableB。这个方法最简单,但大表的话性能可能不如前面的方法,适合数据量不大的场景。事后补加唯一约束/主键(长远方案)
如果以后还要频繁做这种合并操作,建议给主表添加一个基于所有列的唯一约束,或者找出一组能唯一标识记录的列作为组合主键。这样后续再插入数据时,数据库会自动帮你拦截重复记录,也能让你的去重逻辑更简单。
内容的提问来源于stack exchange,提问作者Hakka-4

