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

SQL Server如何统计EXEC动态SQL实际成功修改的表数量?

实现方案

原脚本存在3个核心问题,无法满足需求:

  • 变量赋值逻辑错误:@ExpectedCounter初始值设为0后未重新赋值,和待修改数量永远无法匹配
  • 未使用显式事务:SQL Server中DDL语句默认自动提交,已经执行成功的修改无法回滚
  • 批量拼接执行缺陷:所有ALTER语句合并为单个批处理执行时,任意一条语句失败会直接终止整个批处理,无法统计实际成功条数,也无法定位失败位置

可通过「逐语句执行+异常捕获+显式事务」的方式实现需求,完整脚本如下:

USE FXecute
GO
SET NOCOUNT ON;
SET XACT_ABORT ON; -- 遇到严重错误时自动回滚当前事务,避免孤立事务遗留

DECLARE @ExpectedCounter INT = 0, 
        @ActualSuccessCounter INT = 0,
        @CurrentCmd VARCHAR(MAX),
        @CurrentOrder INT = 1,
        @TotalCmd INT = 0,
        @ErrorMsg NVARCHAR(MAX);

-- 生成待执行修改列表
DROP TABLE IF EXISTS #List
CREATE TABLE #List (
    Command varchar(max), 
    SchemaName SYSNAME,
    TableName SYSNAME,
    ColumnName SYSNAME,
    OrderBy INT IDENTITY(1,1)
)
    
INSERT INTO #List (Command, SchemaName, TableName, ColumnName)
 SELECT  
'ALTER TABLE ['+TABLE_SCHEMA+'].['+TABLE_NAME+'] ALTER COLUMN ['+COLUMN_NAME+'] DECIMAL(22,6)' AS Command,
TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
FROM FXecute.INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'DECIMAL' 
AND (column_name  LIKE  '%amount%' or column_name  LIKE  '%amt%' OR column_name  LIKE  '%total%' OR column_name  LIKE  '%USD%') 
AND TABLE_NAME NOT LIKE 'syncobj%'

-- 赋值预期执行数:默认按列修改条数统计
SET @ExpectedCounter = @@ROWCOUNT;
SET @TotalCmd = @ExpectedCounter;
PRINT '预期修改列数:' + CAST(@ExpectedCounter AS NVARCHAR(10));
-- 如果需要按表数量统计,放开下面两行注释
-- SELECT @ExpectedCounter = COUNT(DISTINCT SchemaName+'.'+TableName) FROM #List
-- PRINT '预期修改表数:' + CAST(@ExpectedCounter AS NVARCHAR(10));

-- 开启显式事务
BEGIN TRANSACTION;

WHILE @CurrentOrder <= @TotalCmd
BEGIN
    SELECT @CurrentCmd = Command FROM #List WHERE OrderBy = @CurrentOrder;
    BEGIN TRY
        EXEC(@CurrentCmd);
        -- 语句执行成功,成功计数+1
        SET @ActualSuccessCounter = @ActualSuccessCounter + 1;
        PRINT '执行成功:' + @CurrentCmd;
    END TRY
    BEGIN CATCH
        -- 捕获错误信息
        SET @ErrorMsg = N'执行失败,语句:' + @CurrentCmd + CHAR(13) + N'错误信息:' + ERROR_MESSAGE();
        PRINT @ErrorMsg;
        -- 出错后直接终止循环
        BREAK;
    END CATCH

    SET @CurrentOrder = @CurrentOrder + 1;
END

-- 结果比对与事务处理
IF @ActualSuccessCounter = @ExpectedCounter AND @ErrorMsg IS NULL
BEGIN
    PRINT '所有修改执行成功,提交事务';
    COMMIT TRANSACTION;
END
ELSE
BEGIN
    PRINT '执行未达到预期,回滚所有修改;实际成功条数:' + CAST(@ActualSuccessCounter AS NVARCHAR(10)) + ',预期条数:' + CAST(@ExpectedCounter AS NVARCHAR(10));
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END

DROP TABLE IF EXISTS #List;
GO

关键说明

  • 如果需要按修改的表数量而非列修改次数做比对,除了调整预期计数为去重表数外,还需要在执行完成后统计实际成功执行过的去重表数量,替换比对逻辑中的@ActualSuccessCounter即可,避免同一张表多个列修改时计数重复
  • SET XACT_ABORT ON必须开启,避免出现运行时错误导致事务无法正常提交/回滚
  • 逐行循环执行虽然比批量拼接执行稍慢,但可以精准定位失败语句,也能准确统计成功数量,是满足校验回滚需求的最稳妥方式
  • ALTER COLUMN操作会持有对应表的架构修改锁,执行期间会阻塞其他会话对目标表的访问,建议在业务低峰期运行

内容的提问来源于stack exchange,提问作者Vivek Nuna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:03:15