当 EXECUTE IMMEDIATE 没有返回任何行时,“ORA-01007:变量不在选择列表中”

Posted

技术标签:

【中文标题】当 EXECUTE IMMEDIATE 没有返回任何行时,“ORA-01007:变量不在选择列表中”【英文标题】:"ORA-01007: variable not in select list" when no rows are returned by EXECUTE IMMEDIATE 【发布时间】:2017-04-05 10:32:10 【问题描述】:

我有一个接收 where 子句作为参数的过程(即where col1 = 1)。我正在使用此子句使用 EXECUTE IMMEDIATE 语句在某些表中进行搜索,并将结果插入到嵌套表中,然后显示。

如果找到任何数据,该过程可以正常工作,但如果没有找到数据,则抛出上述错误。

谁能解释一下导致这个错误的原因?

程序如下:

create or replace procedure prc_checks(pi_where varchar2) as

    cursor c_tables is
        select object_name, 
        case object_name
            when 'XP_IMPORT_MW' THEN 99999999
            when 'XP_IMPORT_MW_ARCH' THEN 99999998
            else TO_NUMBER(SUBSTR(object_name, -8, 8))
        end to_order
        from dba_objects 
        where object_type = 'TABLE' 
        and object_name IN ('XP_IMPORT_MW', 'XP_IMPORT_MW_ARCH') 
        or REGEXP_LIKE (object_name, 'XP_IMPORT_MW_ARCH_201(5|6|7)[0-9]4') order by 2 desc;

    type t_result is table of xp_import_mw%rowtype;
    v_result t_result;

    v_sql varchar2(300);

BEGIN  
    for i in c_tables
        loop
            v_sql := 'select * from ' || i.object_name || ' ' || pi_where;
            execute immediate v_sql bulk collect into v_result;

            if v_result.count > 0 
                then 
                    for j in v_result.first .. v_result.last
                    loop
                        dbms_output.put_line(v_result(j).art_nr);
                    end loop;
                    dbms_output.put_line('... the required information was found on table name ' || upper(i.object_name));
                    exit;
            end if;
        end loop;
END prc_checks;

【问题讨论】:

向我们展示 pi_where 的值,并假设 i.object_name 中的任何表都具有与 xp_import_mv 相同的行类型 pi_where给出了一个例子:where col1 = 1 【参考方案1】:

您会发现这是游标找到的表之一,其列数少于xp_import_mw。例如:

create table xp_import_mw (col1 number, art_nr number, dummy number);
create table xp_import_mw_arch_20160102 (col1 number, art_nr number, dummy number);
create table xp_import_mw_arch_20160101 (col1 number, art_nr number);
insert into xp_import_mw_arch_20160101 values (1, 42); 

所以xp_import_mw 主表有三列但没有匹配的数据。其中一个旧存档表的列数减少了。

我在过程中添加了一个dbms_output.put_line(v_sql),以查看它针对哪个表失败,然后运行它:

set serveroutput on
exec prc_checks('where col1 = 1');

得到输出:

select * from XP_IMPORT_MW where col1 = 1
select * from XP_IMPORT_MW_ARCH_20160102 where col1 = 1
select * from XP_IMPORT_MW_ARCH_20160101 where col1 = 1

Error starting at line : 49 in command -
BEGIN prc_checks('where col1 = 1'); END;
Error report -
ORA-01007: variable not in select list
ORA-06512: at "MY_SCHEMA.PRC_CHECKS", line 25
ORA-06512: at line 1
01007. 00000 -  "variable not in select list"
*Cause:    
*Action:

所以问题不在于没有找到数据;问题是在一个结构错误的表中有匹配的数据。

您可以根据xp_import_mw 表的结构构造选择列表,而不是使用*;这不会阻止它失败,但至少会给你一个更有用的错误消息 - 在这种情况下是 ORA-00904: "DUMMY": invalid identifier 而不是 ORA-01007。

您可以通过以下方式快速粗略地检查差异:

select table_name, count(column_id) as column_count,
  listagg(column_name, ',') within group (order by column_id) as columns
from dba_tab_columns
where table_name IN ('XP_IMPORT_MW', 'XP_IMPORT_MW_ARCH') 
or REGEXP_LIKE (table_name, 'XP_IMPORT_MW_ARCH_201(5|6|7)[0-9]4')
group by table_name
having count(column_id) != (
  select count(column_id) from dba_tab_columns where table_name = 'XP_IMPORT_MW'
);

...尽管如果您使用的是dba_*all_* 视图,您确实应该在此处和您的程序中包含所有者。

【讨论】:

确实,表结构之间存在差异。懒惰的我没有检查每个表中的字段数,并且存在差异。这些表有 649、651、653 列。 我正在尝试您的最后一个选择语句,我收到与“ORA-00923:未在预期位置找到 FROM 关键字”相关的错误。你有什么线索吗? 我猜你使用的是 10g(或更早版本),所以 listagg 不可用......对于 650 列,结果对于 SQL 字符串来说太长了。您可以删除它并进行计数,但您似乎已经知道计数。

以上是关于当 EXECUTE IMMEDIATE 没有返回任何行时,“ORA-01007:变量不在选择列表中”的主要内容,如果未能解决你的问题,请参考以下文章

通过 EXECUTE IMMEDIATE 从 select 语句中返回一个值

oracle使用execute immediate方式完成函数动态传入表名并操作 返回新的主键id值

Oracle 的 EXECUTE IMMEDIATE 与存储过程中的 LIKE 子句

oracle EXECUTE IMMEDIATE动态执行sql及异常信息打印

oracle EXECUTE IMMEDIATE动态执行sql及异常信息打印

如何只使用一次 EXECUTE IMMEDIATE 创建 2 个表?