首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ORA-00905缺失关键字

ORA-00905缺失关键字
EN

Stack Overflow用户
提问于 2016-04-28 07:54:58
回答 3查看 2.3K关注 0票数 0

我试图通过sql文件在sqlplus中执行以下代码:

代码语言:javascript
复制
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;
/

但是,在运行脚本之后,我将得到以下错误:

代码语言:javascript
复制
begin
*
ERROR at line 1:
ORA-00905 missing keyword

check_condition过程如下所示,它基本上验证所提供的条件是否为真。

代码语言:javascript
复制
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;
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-28 15:10:49

问题不在于您在匿名块中显示的动态SQL --如果使用dbms_sql可以使用execute immediate,但这两种方法都是有效的(如果不常见的话)。而且它也与SQL*Plus绑定变量声明或用法无关,尽管如此,使用本地PL/SQL变量而不是客户端绑定变量(就像在过程中那样)更常见,因为不需要在匿名块之外知道c的值。但这两种方法都是可行的。

问题在于您调用tkzpwfsync.wait()。您传递的字符串被用作另一个动态查询的一部分,而抛出ORA-00905的是生成的查询。

在您的过程中,您的块获得了比您已经显示的更多的错误细节:

代码语言:javascript
复制
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语句:

代码语言:javascript
复制
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':

代码语言:javascript
复制
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"

实际上,您也没有执行查询- 执行DDL吗? (因此您在匿名块中的授权可以工作),但是不执行DML。如果满足了,那么它将得到一个ORA-01403,如果条件不满足;在这里使用聚合更安全,所以您总是得到一行返回。

您可以修改该过程以执行以下操作:

代码语言:javascript
复制
  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);

因此,它变成:

代码语言:javascript
复制
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。

如@Mottor所示,在这里使用execute immediate也更简单:

代码语言:javascript
复制
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而不是本机执行是有原因的。

但是,我不确定等待是否真的是必要的;在创建用户时,条目将被添加到该视图中,因此在进行调用之前它们都将存在。对于带有修改后的过程名的检查(而不是等待)来说,这更有意义,但仍然不确定它是否有必要--如果计数不匹配,那么就会因为授权失败而引发错误,或者您已经拥有了SYSDBA特权的用户。所以计数会更高。只是看起来不太有用。(我甚至不会问你为什么需要98个SYSDBA用户;希望你只是在做实验,但如果是这样的话,我会使用一个不那么危险的角色)。

票数 1
EN

Stack Overflow用户

发布于 2016-04-28 08:08:06

尝尝这个。希望能帮上忙。

代码语言:javascript
复制
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;
    /
票数 1
EN

Stack Overflow用户

发布于 2016-04-29 08:04:16

使用问汤姆查看dbms_sql.parse示例

你不能选择..。变成..。在动态sql中。您只需选择并绑定输出列。

下面是“立即执行”:

代码语言:javascript
复制
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;
/

只需说明,此程序不等待,只检查条件。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36908560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档