Oracle Execute Immediate存变量报错:数据类型不一致及结果输出问题
解决方案:捕获动态SQL结果并输出
你的问题核心是动态SQL执行后没有捕获返回的多列结果,仅用单个变量接收必然导致类型不匹配。需要为动态SQL返回的每一列定义对应类型的变量,再通过EXECUTE IMMEDIATE ... INTO ...将结果存入变量,最后拼接输出。
修改后的完整脚本
set serveroutput on; DECLARE v_Schema ALL_TAB_COLUMNS.OWNER%TYPE; v_Table ALL_TAB_COLUMNS.TABLE_NAME%TYPE; v_columnName ALL_TAB_COLUMNS.COLUMN_NAME%TYPE; v_columnPosition ALL_TAB_COLUMNS.COLUMN_ID%TYPE; v_dataType ALL_TAB_COLUMNS.DATA_TYPE%TYPE; v_sql varchar2(4000); -- 新增变量:对应动态SQL返回的每一列类型 v_TableName varchar2(128); v_ColumnName varchar2(128); v_ColumnPosition varchar2(10); v_CountNulls number; v_CountnonNulls number; v_TotalRows number; v_PercentNull number; v_PercentNotNull number; CURSOR c1 IS SELECT OWNER, TABLE_NAME, COLUMN_NAME, COLUMN_ID, DATA_TYPE FROM ALL_TAB_COLUMNS WHERE OWNER = '<my_schema>' AND table_name='<my_table>'; BEGIN OPEN c1; LOOP FETCH c1 INTO v_Schema, v_Table, v_columnName, v_columnPosition, v_dataType; EXIT WHEN c1%NOTFOUND; v_sql := 'SELECT ''' || v_Table || ''' AS TableName ' ||',''' || v_columnName || ''' AS ColumnName ' ||',''' || TO_CHAR(v_columnPosition) || ''' AS ColumnPosition ' ||',COUNT(CASE WHEN ' || v_columnName || ' IS NULL THEN 1 ELSE NULL END) AS CountNulls' ||',COUNT(CASE WHEN ' || v_columnName || ' IS NULL THEN NULL ELSE 1 END) AS CountnonNulls ' ||',COUNT(*) AS TotalRows ' -- 修正百分比计算逻辑,避免除零并确保结果是百分比 ||',ROUND(CASE WHEN COUNT(*) = 0 THEN 0 ELSE COUNT(CASE WHEN ' || v_columnName || ' IS NULL THEN 1 ELSE NULL END)/COUNT(*)*100 END, 2) AS PercentNull ' ||',ROUND(CASE WHEN COUNT(*) = 0 THEN 0 ELSE COUNT(CASE WHEN ' || v_columnName || ' IS NOT NULL THEN 1 ELSE NULL END)/COUNT(*)*100 END, 2) AS PercentNotNull ' || 'FROM ' || v_Schema || '.' || v_Table; -- 加上Schema避免表名冲突 -- 执行动态SQL并将结果存入对应变量 EXECUTE IMMEDIATE v_sql INTO v_TableName, v_ColumnName, v_ColumnPosition, v_CountNulls, v_CountnonNulls, v_TotalRows, v_PercentNull, v_PercentNotNull; -- 格式化输出结果 DBMS_OUTPUT.PUT_LINE('表名: ' || v_TableName); DBMS_OUTPUT.PUT_LINE('列名: ' || v_ColumnName); DBMS_OUTPUT.PUT_LINE('列位置: ' || v_ColumnPosition); DBMS_OUTPUT.PUT_LINE('空值数量: ' || v_CountNulls); DBMS_OUTPUT.PUT_LINE('非空值数量: ' || v_CountnonNulls); DBMS_OUTPUT.PUT_LINE('总行数: ' || v_TotalRows); DBMS_OUTPUT.PUT_LINE('空值占比: ' || v_PercentNull || '%'); DBMS_OUTPUT.PUT_LINE('非空值占比: ' || v_PercentNotNull || '%'); DBMS_OUTPUT.PUT_LINE('----------------------------------------'); END LOOP; CLOSE c1; END; /
关键修改点说明
- 新增对应类型的变量:根据动态SQL返回的8列,定义了8个匹配类型的变量(字符串、数字),解决类型不匹配问题。
- 修正动态SQL的Schema引用:原脚本只写了表名,加上
v_Schema || '.'避免不同Schema下的表名冲突。 - 优化百分比计算:用
CASE WHEN COUNT(*) =0 THEN 0替代原脚本的怪异逻辑,避免除零错误,同时用ROUND保留两位小数让结果更直观。 - 捕获并输出结果:通过
EXECUTE IMMEDIATE ... INTO ...将动态SQL的一行结果存入变量,再用DBMS_OUTPUT.PUT_LINE逐行输出统计信息。
内容的提问来源于stack exchange,提问作者Retnuh
相关产品推荐
相关产品推荐

