You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用T-SQL程序化对比两张表的完整定义?

可以用T-SQL程序化对比两张表的完整定义

当然可以实现,sp_help返回的所有表定义信息都能通过SQL Server的系统视图/函数提取,然后通过集合操作或连接查询找出两张表的差异。下面是具体的实现思路和代码示例,覆盖sp_help返回的核心内容:

核心思路

sp_help的结果集本质是查询系统元数据视图生成的,所以我们可以直接从sys.tables、sys.columns、sys.indexes等系统对象中提取对应信息,然后对两张表的同类元数据做对比。

具体实现示例

下面的代码会分模块对比列定义、索引/主键、外键、检查约束、触发器等核心内容,你可以封装成存储过程或脚本执行。

1. 对比列定义(含数据类型、空值、默认值、标识列)

DECLARE @SchemaName1 NVARCHAR(128) = 'dbo', @TableName1 NVARCHAR(128) = 'TableA';
DECLARE @SchemaName2 NVARCHAR(128) = 'dbo', @TableName2 NVARCHAR(128) = 'TableB';

-- 表1独有的列定义
SELECT 'TableA 独有列' AS diff_type,
       c.name AS column_name,
       t.name AS data_type,
       CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(10)) END AS max_length,
       CAST(c.precision AS VARCHAR(10)) AS precision,
       CAST(c.scale AS VARCHAR(10)) AS scale,
       CASE c.is_nullable WHEN 1 THEN '允许空' ELSE '不允许空' END AS is_nullable,
       ISNULL(dc.definition, '') AS default_value,
       CASE c.is_identity WHEN 1 THEN '是' ELSE '否' END AS is_identity,
       ISNULL(CAST(IDENT_SEED(QUOTENAME(@SchemaName1) + '.' + QUOTENAME(@TableName1)) AS VARCHAR(20)), '') AS identity_seed,
       ISNULL(CAST(IDENT_INCR(QUOTENAME(@SchemaName1) + '.' + QUOTENAME(@TableName1)) AS VARCHAR(20)), '') AS identity_increment
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.columns c ON o.object_id = c.object_id
JOIN sys.types t ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id
LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1
EXCEPT
SELECT 'TableA 独有列' AS diff_type,
       c.name AS column_name,
       t.name AS data_type,
       CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(10)) END AS max_length,
       CAST(c.precision AS VARCHAR(10)) AS precision,
       CAST(c.scale AS VARCHAR(10)) AS scale,
       CASE c.is_nullable WHEN 1 THEN '允许空' ELSE '不允许空' END AS is_nullable,
       ISNULL(dc.definition, '') AS default_value,
       CASE c.is_identity WHEN 1 THEN '是' ELSE '否' END AS is_identity,
       ISNULL(CAST(IDENT_SEED(QUOTENAME(@SchemaName2) + '.' + QUOTENAME(@TableName2)) AS VARCHAR(20)), '') AS identity_seed,
       ISNULL(CAST(IDENT_INCR(QUOTENAME(@SchemaName2) + '.' + QUOTENAME(@TableName2)) AS VARCHAR(20)), '') AS identity_increment
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.columns c ON o.object_id = c.object_id
JOIN sys.types t ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id
LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2

UNION ALL

-- 表2独有的列定义
SELECT 'TableB 独有列' AS diff_type,
       c.name AS column_name,
       t.name AS data_type,
       CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(10)) END AS max_length,
       CAST(c.precision AS VARCHAR(10)) AS precision,
       CAST(c.scale AS VARCHAR(10)) AS scale,
       CASE c.is_nullable WHEN 1 THEN '允许空' ELSE '不允许空' END AS is_nullable,
       ISNULL(dc.definition, '') AS default_value,
       CASE c.is_identity WHEN 1 THEN '是' ELSE '否' END AS is_identity,
       ISNULL(CAST(IDENT_SEED(QUOTENAME(@SchemaName2) + '.' + QUOTENAME(@TableName2)) AS VARCHAR(20)), '') AS identity_seed,
       ISNULL(CAST(IDENT_INCR(QUOTENAME(@SchemaName2) + '.' + QUOTENAME(@TableName2)) AS VARCHAR(20)), '') AS identity_increment
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.columns c ON o.object_id = c.object_id
JOIN sys.types t ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id
LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2
EXCEPT
SELECT 'TableB 独有列' AS diff_type,
       c.name AS column_name,
       t.name AS data_type,
       CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(10)) END AS max_length,
       CAST(c.precision AS VARCHAR(10)) AS precision,
       CAST(c.scale AS VARCHAR(10)) AS scale,
       CASE c.is_nullable WHEN 1 THEN '允许空' ELSE '不允许空' END AS is_nullable,
       ISNULL(dc.definition, '') AS default_value,
       CASE c.is_identity WHEN 1 THEN '是' ELSE '否' END AS is_identity,
       ISNULL(CAST(IDENT_SEED(QUOTENAME(@SchemaName1) + '.' + QUOTENAME(@TableName1)) AS VARCHAR(20)), '') AS identity_seed,
       ISNULL(CAST(IDENT_INCR(QUOTENAME(@SchemaName1) + '.' + QUOTENAME(@TableName1)) AS VARCHAR(20)), '') AS identity_increment
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.columns c ON o.object_id = c.object_id
JOIN sys.types t ON c.system_type_id = t.system_type_id AND c.user_type_id = t.user_type_id
LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1;

2. 对比索引与主键定义

-- 表1独有的索引/主键
SELECT 'TableA 独有索引' AS diff_type,
       i.name AS index_name,
       i.type_desc AS index_type,
       STRING_AGG(c.name, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS key_columns,
       STRING_AGG(CASE WHEN ic.is_included_column = 1 THEN c.name ELSE NULL END, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS included_columns,
       CASE i.is_unique WHEN 1 THEN '唯一' ELSE '非唯一' END AS is_unique,
       CASE i.is_primary_key WHEN 1 THEN '主键' ELSE '非主键' END AS is_primary_key,
       CAST(i.fill_factor AS VARCHAR(3)) AS fill_factor
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.indexes i ON o.object_id = i.object_id
JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
JOIN sys.columns c ON o.object_id = c.object_id AND ic.column_id = c.column_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1 AND i.type <> 0 -- 排除堆表的默认索引
GROUP BY i.name, i.type_desc, i.is_unique, i.is_primary_key, i.fill_factor
EXCEPT
SELECT 'TableA 独有索引' AS diff_type,
       i.name AS index_name,
       i.type_desc AS index_type,
       STRING_AGG(c.name, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS key_columns,
       STRING_AGG(CASE WHEN ic.is_included_column = 1 THEN c.name ELSE NULL END, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS included_columns,
       CASE i.is_unique WHEN 1 THEN '唯一' ELSE '非唯一' END AS is_unique,
       CASE i.is_primary_key WHEN 1 THEN '主键' ELSE '非主键' END AS is_primary_key,
       CAST(i.fill_factor AS VARCHAR(3)) AS fill_factor
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.indexes i ON o.object_id = i.object_id
JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
JOIN sys.columns c ON o.object_id = c.object_id AND ic.column_id = c.column_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2 AND i.type <> 0
GROUP BY i.name, i.type_desc, i.is_unique, i.is_primary_key, i.fill_factor

UNION ALL

-- 表2独有的索引/主键
SELECT 'TableB 独有索引' AS diff_type,
       i.name AS index_name,
       i.type_desc AS index_type,
       STRING_AGG(c.name, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS key_columns,
       STRING_AGG(CASE WHEN ic.is_included_column = 1 THEN c.name ELSE NULL END, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS included_columns,
       CASE i.is_unique WHEN 1 THEN '唯一' ELSE '非唯一' END AS is_unique,
       CASE i.is_primary_key WHEN 1 THEN '主键' ELSE '非主键' END AS is_primary_key,
       CAST(i.fill_factor AS VARCHAR(3)) AS fill_factor
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.indexes i ON o.object_id = i.object_id
JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
JOIN sys.columns c ON o.object_id = c.object_id AND ic.column_id = c.column_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2 AND i.type <> 0
GROUP BY i.name, i.type_desc, i.is_unique, i.is_primary_key, i.fill_factor
EXCEPT
SELECT 'TableB 独有索引' AS diff_type,
       i.name AS index_name,
       i.type_desc AS index_type,
       STRING_AGG(c.name, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS key_columns,
       STRING_AGG(CASE WHEN ic.is_included_column = 1 THEN c.name ELSE NULL END, ', ') WITHIN GROUP (ORDER BY ic.key_ordinal) AS included_columns,
       CASE i.is_unique WHEN 1 THEN '唯一' ELSE '非唯一' END AS is_unique,
       CASE i.is_primary_key WHEN 1 THEN '主键' ELSE '非主键' END AS is_primary_key,
       CAST(i.fill_factor AS VARCHAR(3)) AS fill_factor
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
JOIN sys.indexes i ON o.object_id = i.object_id
JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
JOIN sys.columns c ON o.object_id = c.object_id AND ic.column_id = c.column_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1 AND i.type <> 0
GROUP BY i.name, i.type_desc, i.is_unique, i.is_primary_key, i.fill_factor;

3. 对比外键约束

-- 表1独有的外键
SELECT 'TableA 独有外键' AS diff_type,
       fk.name AS fk_name,
       c.name AS parent_column,
       OBJECT_NAME(fk.referenced_object_id) AS referenced_table,
       rc.name AS referenced_column
FROM sys.foreign_keys fk
JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
JOIN sys.columns c ON fkc.parent_object_id = c.object_id AND fkc.parent_column_id = c.column_id
JOIN sys.columns rc ON fkc.referenced_object_id = rc.object_id AND fkc.referenced_column_id = rc.column_id
JOIN sys.objects o ON fk.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1
EXCEPT
SELECT 'TableA 独有外键' AS diff_type,
       fk.name AS fk_name,
       c.name AS parent_column,
       OBJECT_NAME(fk.referenced_object_id) AS referenced_table,
       rc.name AS referenced_column
FROM sys.foreign_keys fk
JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
JOIN sys.columns c ON fkc.parent_object_id = c.object_id AND fkc.parent_column_id = c.column_id
JOIN sys.columns rc ON fkc.referenced_object_id = rc.object_id AND fkc.referenced_column_id = rc.column_id
JOIN sys.objects o ON fk.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2

UNION ALL

-- 表2独有的外键
SELECT 'TableB 独有外键' AS diff_type,
       fk.name AS fk_name,
       c.name AS parent_column,
       OBJECT_NAME(fk.referenced_object_id) AS referenced_table,
       rc.name AS referenced_column
FROM sys.foreign_keys fk
JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
JOIN sys.columns c ON fkc.parent_object_id = c.object_id AND fkc.parent_column_id = c.column_id
JOIN sys.columns rc ON fkc.referenced_object_id = rc.object_id AND fkc.referenced_column_id = rc.column_id
JOIN sys.objects o ON fk.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2
EXCEPT
SELECT 'TableB 独有外键' AS diff_type,
       fk.name AS fk_name,
       c.name AS parent_column,
       OBJECT_NAME(fk.referenced_object_id) AS referenced_table,
       rc.name AS referenced_column
FROM sys.foreign_keys fk
JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
JOIN sys.columns c ON fkc.parent_object_id = c.object_id AND fkc.parent_column_id = c.column_id
JOIN sys.columns rc ON fkc.referenced_object_id = rc.object_id AND fkc.referenced_column_id = rc.column_id
JOIN sys.objects o ON fk.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1;

4. 对比检查约束

-- 表1独有的检查约束
SELECT 'TableA 独有检查约束' AS diff_type,
       cc.name AS constraint_name,
       cc.definition
FROM sys.check_constraints cc
JOIN sys.objects o ON cc.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1
EXCEPT
SELECT 'TableA 独有检查约束' AS diff_type,
       cc.name AS constraint_name,
       cc.definition
FROM sys.check_constraints cc
JOIN sys.objects o ON cc.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2

UNION ALL

-- 表2独有的检查约束
SELECT 'TableB 独有检查约束' AS diff_type,
       cc.name AS constraint_name,
       cc.definition
FROM sys.check_constraints cc
JOIN sys.objects o ON cc.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName2 AND s.name = @SchemaName2
EXCEPT
SELECT 'TableB 独有检查约束' AS diff_type,
       cc.name AS constraint_name,
       cc.definition
FROM sys.check_constraints cc
JOIN sys.objects o ON cc.parent_object_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = @TableName1 AND s.name = @SchemaName1;

5. 对比触发器

-- 表1独有的触发器
SELECT 'TableA 独有触发器' AS diff_type,
       tr.name AS trigger_name,
       tr.type_desc AS trigger_type,
       tr.create_date
FROM sys.triggers tr
JOIN sys.objects o ON tr.parent_id = o.object_id
JOIN sys.schemas s ON o.schema_id = s.schema_id
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 11:26:19