【发布时间】:2013-05-29 03:15:24
【问题描述】:
我创建了下面的 PL/SQL 存储过程,用于在整个 Oracle11g 数据库中搜索字符串 (srchstr),并将找到该字符串的表和列返回到名为 VALUESEARCHRESULTS 的表中。
该过程已以用户身份通过 SQL Developer 在 Oracle XE 中成功运行。但是,当尝试在 Oracle11g 中以用户 SYS 的身份运行模式 ABC 时,我收到以下错误:
ORA-00911:无效字符 原因:标识符不能以字母和数字以外的任何 ASCII 字符开头。在第一个字符之后也允许使用 $#_。用双引号括起来的标识符可以包含除双引号之外的任何字符。替代引号 (q"#...#") 不能使用空格、制表符或回车作为分隔符。对于所有其他上下文,请参阅 SQL 语言参考手册。
有人知道为什么会这样吗?请在下面查看我的代码。
CREATE OR REPLACE PROCEDURE ABC.FIND_STRING(p_str IN VARCHAR2) authid current_user is
l_query clob;
srchstr varchar2(30) := '';
r_cname varchar2(30) := '';
l_case clob;
l_runquery boolean;
l_tname varchar2(30);
l_cname varchar2(30);
begin
dbms_application_info.set_client_info( '%' || upper(p_str) || '%' );
for x in (select * from user_tables)
loop
l_query := 'select ''' || x.table_name || ''', $$
from ' || x.table_name || '
where rownum = 1 and ( 1=0 ';
l_case := 'case ';
l_runquery := FALSE;
for y in ( select *
from user_tab_columns
where table_name = x.table_name
and (data_type in('CHAR', 'DATE', 'FLOAT', 'NCHAR', 'NUMBER', 'NVARCHAR2', 'VARCHAR2' )
or data_type like 'INTERVAL%' or data_type like 'TIMESTAMP%' )
)
loop
l_runquery := TRUE;
l_query := l_query || ' or upper(' || y.column_name ||
') like userenv(''client_info'') ';
l_case := l_case || ' when upper(' || y.column_name ||
') like userenv(''client_info'') then ''' ||
y.column_name || '''';
end loop;
if ( l_runquery )
then
l_case := l_case || ' else NULL end';
l_query := replace( l_query, '$$', l_case ) || ')';
begin
execute immediate l_query into l_tname, l_cname;
r_cname := l_cname;
dbms_application_info.read_client_info(srchstr);
insert into ABC.ValueSearchResults (resulttable, resultcolumn, searchstring) values (x.table_name, r_cname, srchstr);
dbms_output.put_line
( srchstr || ' found in ' || l_tname || '.' || l_cname );
exception
when no_data_found then
dbms_output.put_line
( srchstr || ' has no hits in ' || x.table_name );
end;
end if;
end loop;
end;
EDIT:上面的存储过程编译没有错误。下面的代码通过将值从表传递到存储过程来执行存储过程。运行以下代码时显示错误:
BEGIN
FOR c IN (SELECT ControlValue FROM ABC.ControlValues) LOOP
ABC.FIND_STRING(c.ControlValue);
END LOOP;
END;
【问题讨论】:
-
当您处理动态 SQL 时,记录您正在执行的 SQL 语句非常有帮助,尤其是当您遇到错误时。如果您可以发布生成的失败的 SQL 语句,则更容易找出错误所在。我的赌注是您有一些区分大小写的标识符,因此您需要将动态 SQL 语句中的表名和列名用双引号引起来。另外,我无法想象您为什么要让用户在 NUMBER 或 DATE 或 TIMESTAMP 列中搜索特定字符串——这似乎不合理。
-
谢谢贾斯汀 - 我已经更新了我的问题以包含执行存储过程的代码。我已经包含了 NUMBER、DATE 和 TIMESTAMP,因为在某些情况下我会搜索数字、日期等。我也会尝试使用双引号。
-
调用存储过程的代码不是那么有趣。您需要记录并发布到
EXECUTE IMMEDIATE的 SQL 语句。鉴于您接受字符串作为参数,您将如何使用此函数搜索DATE。如果您传入字符串“2013 年 3 月 1 日”,则您的函数需要知道字符串的格式并在进行比较之前调用to_char( date_column, 'Month DD YYYY"。除非您希望结果根据会话的NLS_DATE_FORMAT和NLS_TIMESTAMP_FORMAT而有所不同。 -
很多问题...“...当尝试在 Oracle11g 中以 SYS 用户身份运行它时,用于模式 ABC ...”您的意思是您通过以用户 SYS 身份连接来执行此过程,并且执行这个?如果您这样做,您将如何为特定模式运行它?似乎您需要接受架构名称并查询 ALL_TABLES 而不是 USER_TABLES,并且还要指定 DROPPED = 'NO'。为什么要使用字符串设置 client_info?
-
我只搜索保证在数据库中的值。所以对于日期,我总是有正确的日期格式。至于传递给立即执行的语句,它是在存储过程的开头创建的。
标签: oracle stored-procedures plsql oracle11g ora-00911