如何通过SQL存储过程对比同表中两个ID对应的行并返回JSON格式的差异列数据
解决方案:对比同表两行数据差异并返回指定JSON格式的存储过程
我来给你设计一个规范的存储过程实现方案,完全满足你对比同表两行数据差异、并返回指定JSON格式的需求。
核心思路
- 先通过两个ID获取目标行的所有数据,避免重复查询
- 动态读取表的列信息(不用硬编码列名,适配不同表结构)
- 逐列对比两行的值,专门处理NULL值的特殊差异场景
- 将差异列和对应值组装成你需要的JSON数组结构
完整存储过程代码
CREATE PROCEDURE CompareTwoRows @TableName NVARCHAR(128), @IdColumnName NVARCHAR(128), @IdValue1 NVARCHAR(128), @IdValue2 NVARCHAR(128) AS BEGIN SET NOCOUNT ON; -- 声明变量存储动态SQL和列对比片段 DECLARE @Sql NVARCHAR(MAX); DECLARE @ColumnCompareFragments NVARCHAR(MAX); -- 生成每一列的对比逻辑,包含NULL值判断 SELECT @ColumnCompareFragments = STRING_AGG( CONCAT( 'CASE ', 'WHEN ', QUOTENAME(c.COLUMN_NAME), ' <> t2.', QUOTENAME(c.COLUMN_NAME), ' OR (', QUOTENAME(c.COLUMN_NAME), ' IS NULL AND t2.', QUOTENAME(c.COLUMN_NAME), ' IS NOT NULL)', ' OR (', QUOTENAME(c.COLUMN_NAME), ' IS NOT NULL AND t2.', QUOTENAME(c.COLUMN_NAME), ' IS NULL)', ' THEN JSON_OBJECT(''ColumnName'', ''', c.COLUMN_NAME, ''', ''Value1'', ', QUOTENAME(c.COLUMN_NAME), ', ''Value2'', t2.', QUOTENAME(c.COLUMN_NAME), ')', ' END' ), ',' ) FROM INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = @TableName AND c.COLUMN_NAME <> @IdColumnName; -- 排除ID列本身 -- 拼接完整的动态SQL语句 SET @Sql = CONCAT( 'SELECT JSON_QUERY(''['' + STRING_AGG(diff_item, '','') + '']'') AS DifferenceJson ', 'FROM (', ' SELECT t1.*, t2.* ', ' FROM ', QUOTENAME(@TableName), ' t1 ', ' CROSS JOIN ', QUOTENAME(@TableName), ' t2 ', ' WHERE t1.', QUOTENAME(@IdColumnName), ' = ''', @IdValue1, ''' ', ' AND t2.', QUOTENAME(@IdColumnName), ' = ''', @IdValue2, '''', ') target_rows ', 'CROSS APPLY (', ' SELECT ', @ColumnCompareFragments, ' AS diff_item ', ') diff_items ', 'WHERE diff_item IS NOT NULL' ); -- 执行动态SQL EXEC sp_executesql @Sql; END
代码说明
参数解释
@TableName:需要对比数据的目标表名@IdColumnName:表中作为唯一标识的ID列名称(比如你的示例里是Col1)@IdValue1:第一个待对比的ID值(比如Id-1)@IdValue2:第二个待对比的ID值(比如Id-2)
关键细节
- NULL值处理:专门判断了"一方为NULL另一方不为NULL"的场景,避免遗漏这种常见的差异
- 动态列适配:通过
INFORMATION_SCHEMA.COLUMNS自动读取表的所有列,不用手动硬编码列名,适配任意表结构 - JSON合法性:用
JSON_OBJECT生成单个差异项的JSON,再用STRING_AGG拼接成数组,最后通过JSON_QUERY确保输出是标准合法的JSON格式
测试示例(匹配你的数据场景)
假设你的表结构和数据如下:
CREATE TABLE TestTable ( Col1 NVARCHAR(50), Col2 NVARCHAR(50), Col3 INT, Col4 INT, Col5 INT ); INSERT INTO TestTable VALUES ('Id-1', 'ABC', 123, 321, 111), ('Id-2', 'ABC', 333, 321, 123);
调用存储过程:
EXEC CompareTwoRows 'TestTable', 'Col1', 'Id-1', 'Id-2';
返回的JSON结果(和你预期的格式完全一致):
[ { "ColumnName":"Col3", "Value1":"123", "Value2":"333" }, { "ColumnName":"Col5", "Value1":"111", "Value2":"123" } ]
注意事项
- 确保执行存储过程的账号拥有查询
INFORMATION_SCHEMA系统视图的权限 - 如果表中包含特殊数据类型(比如日期、二进制),可以根据需求在
JSON_OBJECT中添加类型转换逻辑(比如CONVERT(NVARCHAR(50), 列名)) - 该存储过程仅查询目标的两行数据,性能表现优秀,适合大表场景
内容的提问来源于stack exchange,提问作者Mysterious288
相关产品推荐
相关产品推荐

