我想检查所有表的所有列,以查找有效日期表中未包含的条目。
换句话说,所有类型为date的列的元素都必须是表列CALENDAR.BD的其中一个条目。
我的问题是select checkAllDateColumns() from DUAL
执行该功能只会产生
表名无效,第16行
我不明白为什么?
CREATE OR REPLACE FUNCTION checkAllDateColumns RETURN NUMBER IS
l_count NUMBER;
BEGIN
FOR t IN (SELECT table_name
FROM all_tables
WHERE owner = 'ASK_QUESTION')
LOOP
dbms_output.put_line ('Current table : ' || t.table_name);
FOR c IN (SELECT column_name
FROM all_tab_columns
WHERE TABLE_NAME = t.table_name AND data_type = 'DATE')
LOOP
execute immediate 'select count(*) from :1 where :2 not in (select BD from CALENDAR where is_business_day = 1)'
into l_count
using t.table_name, c.column_name;
IF (l_count > 0) THEN
RETURN 1;
END IF;
END LOOP;
END LOOP;
RETURN 0;
END checkAllDateColumns;
/
顺便说一句:我对第一次不匹配的声明很好,目前我想弄清楚动态的sql ...
答案 0 :(得分:1)
您不能将绑定变量用于表名或列名,仅用于列值。它试图将:1
解释为标识符,它不使用using
子句中的值。您的returning into
子句也应该只是into
。这有效:
execute immediate 'select count(*) from "' || t.table_name
|| '" where "' || c.column_name
|| '" not in (select BD from CALENDAR where is_business_day = 1)'
into l_count;
你可能使用左连接方法获得性能差异,但这取决于您的数据:
execute immediate 'select count(*) from "' || t.table_name
|| '" t left join calendar c on c.bd = trunc(t."'
|| c.column_name || '") and c.is_business_day = 1 '
|| ' where c.bd is null'
into l_count;
我添加了trunc()
,以防任何字段中有时间;当然,你也可以在其他版本中做同样的事情。
在两者中我都在表和列名称中包含双引号,以防万一有quoted identifiers - 没有那些存在获得ORA-00904'无效标识符'错误的风险。但希望你无论如何都不用担心。
你也不需要嵌套循环;您可以从all_tab_columns
获取表名,或者如果您愿意,可以在单个游标中加入all_tables
和all_tab_columns
。您还应该检查两个表中的owner
是否相同,以防不同模式中有两个版本的表。