T-SQL统计指定表列行数与空值数时,动态执行报错:转换varchar值', '为int失败
报错根因定位
代码中多个逻辑问题叠加触发了类型转换报错:
- 循环初始值与自增序列不匹配:
@BANG表的自增ID从1开始生成,代码中设置@ID初始值为0,首次循环查询不到对应记录,表名、列名全部为NULL,拼接出的动态SQL残留无意义的空值、分隔逗号,直接触发类型转换错误 - 动态SQL拼接逻辑错误:INSERT语句中直接拼接表名、列名字符串,但没有为字符串值加单引号,也没有做对象名转义,同时拼接时
@TOTAL_ROW、@TOTAL_NULL两个变量还未被赋值,生成的SQL语法完全不符合规则 - 执行作用域隔离:
EXEC()开启的独立执行上下文无法访问外部定义的表变量@RESULT、统计变量,就算语法正确也无法正常写入数据
修正后的可运行实现
修正思路:调整循环起始值匹配自增规则,用QUOTENAME转义所有数据库对象名避免语法问题,改用sp_executesql传递输出参数获取统计值,在外部作用域完成结果写入,规避作用域隔离问题。
DECLARE @BANG TABLE ( TABLE_NAME NVARCHAR(128), COLUMN_NAME NVARCHAR(128), ID INT IDENTITY(1, 1) ) INSERT INTO @BANG (TABLE_NAME, COLUMN_NAME) SELECT A.NAME AS TABLE_NAME, B.NAME AS COLUMN_NAME FROM SYS.TABLES AS A INNER JOIN SYS.COLUMNS AS B ON A.OBJECT_ID = B.OBJECT_ID WHERE A.NAME IN ('CTHD', 'HOADON', 'SANPHAM', 'KHACHHANG', 'NHANVIEN') DECLARE @RESULT TABLE ( TABLE_NAME NVARCHAR(128), COLUMN_NAME NVARCHAR(128), TOTAL_ROW INT, TOTAL_NULL INT ) -- 调整循环初始值,匹配自增ID从1开始的规则 DECLARE @ID INT = 1 DECLARE @MAXID INT = (SELECT MAX(ID) FROM @BANG) WHILE @ID <= @MAXID BEGIN DECLARE @TABLE_NAME NVARCHAR(128), @COLUMN_NAME NVARCHAR(128) SELECT @TABLE_NAME = TABLE_NAME, @COLUMN_NAME = COLUMN_NAME FROM @BANG WHERE ID = @ID DECLARE @TOTAL_ROW INT, @TOTAL_NULL INT -- 构建动态SQL,用QUOTENAME转义对象名,通过输出参数返回统计结果 DECLARE @SQL NVARCHAR(MAX) = N' SELECT @TOTAL_ROW_OUT = COUNT(*) FROM ' + QUOTENAME(@TABLE_NAME) + N' SELECT @TOTAL_NULL_OUT = COUNT(*) FROM ' + QUOTENAME(@TABLE_NAME) + N' WHERE ' + QUOTENAME(@COLUMN_NAME) + N' IS NULL ' -- 用sp_executesql传递输出参数,解决作用域隔离问题 EXEC sp_executesql @SQL, N'@TOTAL_ROW_OUT INT OUTPUT, @TOTAL_NULL_OUT INT OUTPUT', @TOTAL_ROW_OUT = @TOTAL_ROW OUTPUT, @TOTAL_NULL_OUT = @TOTAL_NULL OUTPUT -- 在外部作用域写入结果表 INSERT INTO @RESULT (TABLE_NAME, COLUMN_NAME, TOTAL_ROW, TOTAL_NULL) VALUES (@TABLE_NAME, @COLUMN_NAME, @TOTAL_ROW, @TOTAL_NULL) SET @ID += 1 END -- 查询最终统计结果 SELECT * FROM @RESULT
内容的提问来源于stack exchange,提问作者Dustin Nguyen
相关产品推荐
相关产品推荐

