ORA-00905 缺少关键字
ORA-00905 missing keyword
我正在尝试通过 sql 文件在 sqlplus 中执行以下代码:
connect sys/knl_test7 as sysdba
grant sysdba to user1 identified by user1;
grant sysoper to user2 identified by user2;
variable c number;
begin
:c := dbms_sql.open_cursor;
for i in 3 .. 98 loop
dbms_sql.parse(:c, 'grant sysdba to user'||to_char(i)||' identified by user'||to_char(i), dbms_sql.v7);
dbms_lock.sleep(5);
end loop;
dbms_sql.close_cursor(:c);
tkzpwfsync.check_condition('(select count(username) from v$pwfile_users where username like ''USER%'')=98');
end;
/
但是在 运行 脚本之后我收到以下错误:
begin
*
ERROR at line 1:
ORA-00905 missing keyword
check_condition程序如下,主要是验证所提供的条件是否成立。
create or replace package tkzpwfsync is
procedure check_condition(condition varchar2);
end;
/
show errors
create or replace package body tkzpwfsync is
procedure check_condition(condition varchar2) is
x integer;
c number;
begin
x := 0;
c := dbms_sql.open_cursor;
dbms_sql.parse(c,'select 1 into x from dual where '||condition,dbms_sql.v7);
if (x!=1) then raise_application_error(-20001,'Condition '||condition||' is not met.'); end if;
dbms_sql.close_cursor(c);
end;
end;
/
show errors
create public synonym tkzpwfsync for tkzpwfsync;
grant execute on tkzpwfsync to public;
试试这个。希望对你有帮助。
connect sys/knl_test7@DB_NAME as sysdba
grant sysdba to user1 identified by user1;
grant sysoper to user2 identified by user2;
SET SQLBL ON;
SET DEFINE OFF;
BEGIN
FOR i IN 3 .. 98
LOOP
EXECUTE IMMEDIATE 'grant sysdba to user'||TO_CHAR(i)||' identified by "user'||TO_CHAR(i)||'"';
dbms_lock.sleep(5);
END LOOP;
tkzpwfsync.wait('(select count(username) from v$pwfile_users where username like ''USER%'')=98');
END;
/
问题不在于您在匿名块中显示的动态 SQL - 使用 dbms_sql
是有效的,如果可能不寻常的话,可以使用 execute immediate
但两者都有效。而且它与 SQL*Plus 绑定变量声明或用法无关,尽管为此使用本地 PL/SQL 变量而不是客户端绑定变量会更常见(正如您在你的过程),因为 c
的值不需要在匿名块之外知道。但同样有效。
问题出在您对 tkzpwfsync.wait()
的调用上。您传递的字符串用作另一个动态查询的一部分,它是 that 生成的抛出 ORA-00905 的查询。
通过您的程序,您的块获得的错误详细信息比您显示的更多:
begin
*
ERROR at line 1:
ORA-00905: missing keyword
ORA-06512: at "SYS.DBMS_SQL", line 1199
ORA-06512: at "SCHEMA.TKZPWFSYNC.WAIT", line 7
ORA-06512: at line 8
wait()
过程正在尝试解析 SQL 语句:
select 1 into x from dual
where (select count(username) from v$pwfile_users where username like 'USER%')=98
into x
是一个 PL/SQL 结构,而不是 SQL 的一部分。如果你直接 运行 你会看到相同的 ORA-00905 错误,因为它将 'into' 视为列别名,然后不知道如何处理 'x':
select 1 into x from dual
where (select count(username) from v$pwfile_users where username like 'USER%')=98;
Error report -
SQL Error: ORA-00905: missing keyword
00905. 00000 - "missing keyword"
您实际上也没有执行查询 - parse
does execute DDL(因此匿名块中的 g运行t 有效),但不执行 DML。如果它这样做了,那么如果不满足条件,它将得到一个 ORA-01403;在这里使用聚合更安全,因此您总是返回一行。
您可以修改程序来做:
dbms_sql.parse(c,'select count(*) from dual where '||condition,dbms_sql.v7);
dbms_sql.define_column(c, 1, x);
r := dbms_sql.execute(c);
所以它变成:
procedure wait(condition varchar2) is
x integer;
c number;
r integer;
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c,'select count(*) from dual where '||condition,dbms_sql.v7);
dbms_sql.define_column(c, 1, x);
r := dbms_sql.execute(c);
if dbms_sql.fetch_rows(c) > 0 then
dbms_sql.column_value(c, 1, x);
end if;
if (x!=1) then
raise_application_error(-20001,'Condition '||condition||' is not met.');
end if;
dbms_sql.close_cursor(c);
end;
/
现在有效,如果不满足条件,会抛出 ORA-20001。
在这里使用 execute immediate
也更简单,如@Mottor 所示:
procedure wait(condition varchar2) is
x integer;
begin
execute immediate 'select count(*) from dual where '||condition into x;
if (x!=1) then
raise_application_error(-20001,'Condition '||condition||' is not met.');
end if;
end;
/
...但也许您想要使用 dbms_sql.v7
而不是本机执行是有原因的。
虽然我不确定是否真的需要等待;这些条目将在创建用户时添加到该视图中,因此它们将在您进行调用之前全部存在。使用修改后的过程名称作为检查而不是等待更有意义,但仍然不确定是否有必要 - 如果计数不匹配,则 g运行t 已经引发错误失败,或者您已经拥有具有 SYSDBA 权限的用户。所以计数会更高。它似乎不是很有用。 (我什至不会问为什么您需要 98 个具有 SYSDBA 权限的用户;希望您只是在试验,但如果是这样,我会使用危险性较小的角色)。
使用 dbms_sql.parse
查看 Ask Tom 示例
You do not SELECT ... INTO ... in dynamic sql. You just select and bind the output columns.
这里是 EXECUTE IMMEDIATE:
CREATE OR REPLACE PACKAGE BODY POINT_NET.tkzpwfsync
IS
PROCEDURE wait (condition VARCHAR2)
IS
x INTEGER;
BEGIN
x := 0;
EXECUTE IMMEDIATE 'select count(*) from dual where ' || condition INTO x;
IF (x != 1) THEN
raise_application_error (-20001, 'Condition ' || condition || ' is not met.');
END IF;
END;
END;
/
只是提一下,这个程序不等待,只检查条件。
我正在尝试通过 sql 文件在 sqlplus 中执行以下代码:
connect sys/knl_test7 as sysdba
grant sysdba to user1 identified by user1;
grant sysoper to user2 identified by user2;
variable c number;
begin
:c := dbms_sql.open_cursor;
for i in 3 .. 98 loop
dbms_sql.parse(:c, 'grant sysdba to user'||to_char(i)||' identified by user'||to_char(i), dbms_sql.v7);
dbms_lock.sleep(5);
end loop;
dbms_sql.close_cursor(:c);
tkzpwfsync.check_condition('(select count(username) from v$pwfile_users where username like ''USER%'')=98');
end;
/
但是在 运行 脚本之后我收到以下错误:
begin
*
ERROR at line 1:
ORA-00905 missing keyword
check_condition程序如下,主要是验证所提供的条件是否成立。
create or replace package tkzpwfsync is
procedure check_condition(condition varchar2);
end;
/
show errors
create or replace package body tkzpwfsync is
procedure check_condition(condition varchar2) is
x integer;
c number;
begin
x := 0;
c := dbms_sql.open_cursor;
dbms_sql.parse(c,'select 1 into x from dual where '||condition,dbms_sql.v7);
if (x!=1) then raise_application_error(-20001,'Condition '||condition||' is not met.'); end if;
dbms_sql.close_cursor(c);
end;
end;
/
show errors
create public synonym tkzpwfsync for tkzpwfsync;
grant execute on tkzpwfsync to public;
试试这个。希望对你有帮助。
connect sys/knl_test7@DB_NAME as sysdba
grant sysdba to user1 identified by user1;
grant sysoper to user2 identified by user2;
SET SQLBL ON;
SET DEFINE OFF;
BEGIN
FOR i IN 3 .. 98
LOOP
EXECUTE IMMEDIATE 'grant sysdba to user'||TO_CHAR(i)||' identified by "user'||TO_CHAR(i)||'"';
dbms_lock.sleep(5);
END LOOP;
tkzpwfsync.wait('(select count(username) from v$pwfile_users where username like ''USER%'')=98');
END;
/
问题不在于您在匿名块中显示的动态 SQL - 使用 dbms_sql
是有效的,如果可能不寻常的话,可以使用 execute immediate
但两者都有效。而且它与 SQL*Plus 绑定变量声明或用法无关,尽管为此使用本地 PL/SQL 变量而不是客户端绑定变量会更常见(正如您在你的过程),因为 c
的值不需要在匿名块之外知道。但同样有效。
问题出在您对 tkzpwfsync.wait()
的调用上。您传递的字符串用作另一个动态查询的一部分,它是 that 生成的抛出 ORA-00905 的查询。
通过您的程序,您的块获得的错误详细信息比您显示的更多:
begin
*
ERROR at line 1:
ORA-00905: missing keyword
ORA-06512: at "SYS.DBMS_SQL", line 1199
ORA-06512: at "SCHEMA.TKZPWFSYNC.WAIT", line 7
ORA-06512: at line 8
wait()
过程正在尝试解析 SQL 语句:
select 1 into x from dual
where (select count(username) from v$pwfile_users where username like 'USER%')=98
into x
是一个 PL/SQL 结构,而不是 SQL 的一部分。如果你直接 运行 你会看到相同的 ORA-00905 错误,因为它将 'into' 视为列别名,然后不知道如何处理 'x':
select 1 into x from dual
where (select count(username) from v$pwfile_users where username like 'USER%')=98;
Error report -
SQL Error: ORA-00905: missing keyword
00905. 00000 - "missing keyword"
您实际上也没有执行查询 - parse
does execute DDL(因此匿名块中的 g运行t 有效),但不执行 DML。如果它这样做了,那么如果不满足条件,它将得到一个 ORA-01403;在这里使用聚合更安全,因此您总是返回一行。
您可以修改程序来做:
dbms_sql.parse(c,'select count(*) from dual where '||condition,dbms_sql.v7);
dbms_sql.define_column(c, 1, x);
r := dbms_sql.execute(c);
所以它变成:
procedure wait(condition varchar2) is
x integer;
c number;
r integer;
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c,'select count(*) from dual where '||condition,dbms_sql.v7);
dbms_sql.define_column(c, 1, x);
r := dbms_sql.execute(c);
if dbms_sql.fetch_rows(c) > 0 then
dbms_sql.column_value(c, 1, x);
end if;
if (x!=1) then
raise_application_error(-20001,'Condition '||condition||' is not met.');
end if;
dbms_sql.close_cursor(c);
end;
/
现在有效,如果不满足条件,会抛出 ORA-20001。
在这里使用 execute immediate
也更简单,如@Mottor 所示:
procedure wait(condition varchar2) is
x integer;
begin
execute immediate 'select count(*) from dual where '||condition into x;
if (x!=1) then
raise_application_error(-20001,'Condition '||condition||' is not met.');
end if;
end;
/
...但也许您想要使用 dbms_sql.v7
而不是本机执行是有原因的。
虽然我不确定是否真的需要等待;这些条目将在创建用户时添加到该视图中,因此它们将在您进行调用之前全部存在。使用修改后的过程名称作为检查而不是等待更有意义,但仍然不确定是否有必要 - 如果计数不匹配,则 g运行t 已经引发错误失败,或者您已经拥有具有 SYSDBA 权限的用户。所以计数会更高。它似乎不是很有用。 (我什至不会问为什么您需要 98 个具有 SYSDBA 权限的用户;希望您只是在试验,但如果是这样,我会使用危险性较小的角色)。
使用 dbms_sql.parse
查看 Ask Tom 示例You do not SELECT ... INTO ... in dynamic sql. You just select and bind the output columns.
这里是 EXECUTE IMMEDIATE:
CREATE OR REPLACE PACKAGE BODY POINT_NET.tkzpwfsync
IS
PROCEDURE wait (condition VARCHAR2)
IS
x INTEGER;
BEGIN
x := 0;
EXECUTE IMMEDIATE 'select count(*) from dual where ' || condition INTO x;
IF (x != 1) THEN
raise_application_error (-20001, 'Condition ' || condition || ' is not met.');
END IF;
END;
END;
/
只是提一下,这个程序不等待,只检查条件。