我有一个脚本,它生成一个动态语句来捕获给定表中每列的空信息和非空信息。
我能够让脚本最初运行,但只收到消息PL/SQL 过程成功完成。
经过一些额外的研究,看起来我需要将动态查询结果放入一个单独的变量中,并使用 DBMS_OUTPUT.PUTLINE 显示立即执行语句的实际结果。
这是在循环内部,因此它应该只有一个字符串作为要运行的查询结果,所以我认为 BULK COLLECT 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);
v_result varchar2(4000);
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 '
||',COUNT(CASE WHEN ' || v_columnName || ' IS NULL THEN 1 ELSE 0 END) / CASE WHEN COUNT(*) <> 0 THEN COUNT(*) ELSE .001 * 100 END AS PercentNull '
||',COUNT(CASE WHEN ' || v_columnName || ' IS NULL THEN NULL ELSE 1 END) / CASE WHEN COUNT(*) <> 0 THEN COUNT(*) ELSE 0.1 END * 100 AS PercentNotNull '
|| 'FROM ' || v_Table;
EXECUTE IMMEDIATE v_sql;
END LOOP;
CLOSE c1;
END;
通过从 ALL_TAB_COLUMNS 中进行选择,您还将获得 VIEW 和 MATERIALIZED VIEW,并且查询将在所有处于无效状态的对象上失败,您应该 JOIN 于 ALL_TABLES 并仅过滤那些具有“status = 'VALID'”的对象, 但你仍然会得到MV后面的桌子,...
要返回 EXECUTE IMMEDIATE 的结果,只需添加“INTO list_of_variables_you_need_to_declare”即可。
还要注意,您将获得 Oracle 添加的所有用于处理 JSON 索引、MV 日志、全文索引、错误日志等的表。一般来说,它们的名称包含 1 个或多个“$”,您可能需要将它们过滤掉。 (并且无需重新选择您已经知道的列:table_name、column_name、column_position,...)
在任何情况下,添加异常处理和适当的日志记录将帮助您理解边缘情况。