在SQL Server中对比两个表的行值,判断是否存在差异
在SQL Server中对比两个表的行数据差异
嘿,针对你要对比Product1和Product2_Transform两个表任意行任意字段差异的需求,我给你整理了几种实用的SQL Server解决方案:
方法1:使用FULL OUTER JOIN找出所有差异行(含仅单表存在的行)
这种方法会帮你覆盖三种差异场景:
- 两个表都存在但字段值有差异的行
- 仅在Product1存在的行
- 仅在Product2_Transform存在的行
SELECT ISNULL(p1.Product_id, p2.Product_id) AS Product_id, ISNULL(p1.Product_rev, p2.Product_rev) AS Product_rev, -- 标记差异类型 CASE WHEN p1.Product_id IS NULL THEN '仅存在于Product2_Transform' WHEN p2.Product_id IS NULL THEN '仅存在于Product1' ELSE '字段值存在差异' END AS Difference_Type, -- 逐个字段对比,显示具体差异值 CASE WHEN ISNULL(p1.Product_Name, '') <> ISNULL(p2.Product_Name, '') THEN CONCAT('Product1: ', p1.Product_Name, ' | Product2: ', p2.Product_Name) ELSE NULL END AS Product_Name_Diff, CASE WHEN ISNULL(p1.Product_description, '') <> ISNULL(p2.Product_description, '') THEN CONCAT('Product1: ', p1.Product_description, ' | Product2: ', p2.Product_description) ELSE NULL END AS Product_description_Diff, CASE WHEN ISNULL(p1.Product_owner, '') <> ISNULL(p2.Product_owner, '') THEN CONCAT('Product1: ', p1.Product_owner, ' | Product2: ', p2.Product_owner) ELSE NULL END AS Product_owner_Diff, -- Product2_Transform无这两个字段,对比时用空字符串占位 CASE WHEN ISNULL(p1.Product_Group, '') <> '' THEN CONCAT('Product1: ', p1.Product_Group, ' | Product2: 无此字段') ELSE NULL END AS Product_Group_Diff, CASE WHEN ISNULL(p1.Product_TYPE, '') <> '' THEN CONCAT('Product1: ', p1.Product_TYPE, ' | Product2: 无此字段') ELSE NULL END AS Product_TYPE_Diff FROM Product1 p1 FULL OUTER JOIN Product2_Transform p2 ON p1.Product_id = p2.Product_id AND p1.Product_rev = p2.Product_rev WHERE -- 筛选所有存在差异的行 p1.Product_id IS NULL OR p2.Product_id IS NULL OR ISNULL(p1.Product_Name, '') <> ISNULL(p2.Product_Name, '') OR ISNULL(p1.Product_description, '') <> ISNULL(p2.Product_description, '') OR ISNULL(p1.Product_owner, '') <> ISNULL(p2.Product_owner, '') OR ISNULL(p1.Product_Group, '') <> '' OR ISNULL(p1.Product_TYPE, '') <> '';
关键说明:
- 用
ISNULL处理NULL值,避免NULL与非NULL的对比被忽略 - 每个字段的
CASE语句直接展示差异内容,方便快速定位问题 - 针对Product2_Transform没有的字段,专门标注“无此字段”,避免混淆
方法2:用HASHBYTES快速判断整行差异
如果你只需要快速定位有差异的行,不需要具体哪个字段出问题,哈希值对比的效率更高:
SELECT ISNULL(p1.Product_id, p2.Product_id) AS Product_id, ISNULL(p1.Product_rev, p2.Product_rev) AS Product_rev, CASE WHEN p1.Product_id IS NULL THEN '仅存在于Product2_Transform' WHEN p2.Product_id IS NULL THEN '仅存在于Product1' ELSE '字段值存在差异' END AS Difference_Type FROM Product1 p1 FULL OUTER JOIN Product2_Transform p2 ON p1.Product_id = p2.Product_id AND p1.Product_rev = p2.Product_rev WHERE HASHBYTES('SHA2_256', CONCAT( ISNULL(p1.Product_Name, ''), '|', ISNULL(p1.Product_description, ''), '|', ISNULL(p1.Product_owner, ''), '|', ISNULL(p1.Product_Group, ''), '|', ISNULL(p1.Product_TYPE, '') )) <> HASHBYTES('SHA2_256', CONCAT( ISNULL(p2.Product_Name, ''), '|', ISNULL(p2.Product_description, ''), '|', ISNULL(p2.Product_owner, ''), '|', '', '|', -- Product2_Transform无Product_Group,用空字符串占位 '' -- Product2_Transform无Product_TYPE,用空字符串占位 )) OR p1.Product_id IS NULL OR p2.Product_id IS NULL;
关键说明:
- 选择
SHA2_256哈希算法,碰撞概率极低,比CHECKSUM更可靠 - 用
|作为字段分隔符,避免不同字段的内容拼接后产生歧义
方法3:仅对比两表共有的行
如果你只关心两个表都存在的记录(即Product_id和Product_rev完全匹配的行),可以用INNER JOIN缩小范围:
SELECT p1.Product_id, p1.Product_rev, CASE WHEN ISNULL(p1.Product_Name, '') <> ISNULL(p2.Product_Name, '') THEN CONCAT('Product1: ', p1.Product_Name, ' | Product2: ', p2.Product_Name) ELSE NULL END AS Product_Name_Diff, CASE WHEN ISNULL(p1.Product_description, '') <> ISNULL(p2.Product_description, '') THEN CONCAT('Product1: ', p1.Product_description, ' | Product2: ', p2.Product_description) ELSE NULL END AS Product_description_Diff, CASE WHEN ISNULL(p1.Product_owner, '') <> ISNULL(p2.Product_owner, '') THEN CONCAT('Product1: ', p1.Product_owner, ' | Product2: ', p2.Product_owner) ELSE NULL END AS Product_owner_Diff, CASE WHEN ISNULL(p1.Product_Group, '') <> '' THEN CONCAT('Product1: ', p1.Product_Group, ' | Product2: 无此字段') ELSE NULL END AS Product_Group_Diff, CASE WHEN ISNULL(p1.Product_TYPE, '') <> '' THEN CONCAT('Product1: ', p1.Product_TYPE, ' | Product2: 无此字段') ELSE NULL END AS Product_TYPE_Diff FROM Product1 p1 INNER JOIN Product2_Transform p2 ON p1.Product_id = p2.Product_id AND p1.Product_rev = p2.Product_rev WHERE ISNULL(p1.Product_Name, '') <> ISNULL(p2.Product_Name, '') OR ISNULL(p1.Product_description, '') <> ISNULL(p2.Product_description, '') OR ISNULL(p1.Product_owner, '') <> ISNULL(p2.Product_owner, '') OR ISNULL(p1.Product_Group, '') <> '' OR ISNULL(p1.Product_TYPE, '') <> '';
性能提示:
如果表数据量较大,记得给Product_id和Product_rev建立联合索引,能大幅提升JOIN操作的速度。
内容的提问来源于stack exchange,提问作者badri




