如果它们在businessday日历中,请检查DATE类型列的所有条目

时间:2014-04-17 14:44:39

标签: oracle dynamic-sql

我想检查所有表的所有列,以查找有效日期表中未包含的条目。

换句话说,所有类型为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 ...

1 个答案:

答案 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_tablesall_tab_columns。您还应该检查两个表中的owner是否相同,以防不同模式中有两个版本的表。