调用 Oracle 存储过程中的参数数量或类型错误

wrong number or types of arguments in call to Oracle stored procedure

提问人:Andrew 提问时间:10/11/2021 更新时间:10/11/2021 访问量:318

问:

我在下面创建了 Oracle 参数化存储过程,我试图在其中将表权限授予另一个用户,但收到错误为 .Truncatewrong number or types of arguments in call to DO_TRUNCATE

create or replace procedure "DWH_02"."DO_TRUNCATE" (truncate_tablename NVARCHAR2)
IS
begin
 EXECUTE IMMEDIATE 'TRUNCATE TABLE' || truncate_tablename;
 EXECUTE IMMEDIATE 'grant execute on ' || DWH_02.DO_TRUNCATE ||' TO DWH_ST';
end;
/
Oracle 存储过程 参数传递 execute-immediate

评论


答:

1赞 MT0 10/11/2021 #1

语句中缺少空格字符,过程名称应位于语句的字符串文本中(而不是尝试动态追加它):TRUNCATEGRANT

create or replace procedure "DWH_02"."DO_TRUNCATE" (truncate_tablename NVARCHAR2)
IS
begin
 EXECUTE IMMEDIATE 'TRUNCATE TABLE ' || truncate_tablename;
 --                               ^ Here
 EXECUTE IMMEDIATE 'grant execute on DWH_02.DO_TRUNCATE TO DWH_ST';
end;
/

我也不确定在程序中包括它的价值是什么。您只需要运行一次,并且可以在过程之外使用特权用户执行此操作;显然没有必要将其包含在程序中。GRANTGRANT

评论

0赞 Andrew 10/11/2021
@MTO谢谢......实际上,我想将截断权限授予用户DWH_ST的所有表...你还有其他更好的方法来做到这一点吗?
0赞 Andrew 10/11/2021
我应该做这样的事情吗?创建或替换过程 do_truncate (truncate_tablename NVARCHAR2) as begin EXECUTE IMMEDIATE 'TRUNCATE TABLE ' ||truncate_tablename;结束;/ 执行do_truncate('TEST_TBL');
0赞 MT0 10/11/2021
@Andrew 是的,然后只需运行该过程,以授予 Alice(或任何人)运行该过程的权限。无需在每次运行该过程时重新授予该权限。或者更糟糕的是,如果该过程仍在授予权限,并且您更改了谁应该负责截断表并手动撤消该用户的权限,那么下次其他人运行该过程时,它将重新授予该权限,并且用户将有权访问他们不应该访问的内容。GRANT EXECUTE ON DWH_02.DO_TRUNCATE TO ALICE;
0赞 Andrew 10/11/2021
@MTO我不知道我以某种方式收到错误,即使我尝试以与我提到的相同的方式授予,特权不足
0赞 Andrew 10/11/2021
我知道我还需要 DROP 任何缺少的特权。.
1赞 Roberto Hernandez 10/11/2021 #2

同一解决方案的另一个版本,对如何截断表和调试以查看执行的命令有更多的控制权。

让我向您展示演示

SQL> create table test3.t1 ( c1 number, c2 number ) ;

Table created.

SQL> insert into test3.t1 select level, level from dual connect by level <= 10000 ;

10000 rows created.

然后我创建自己的截断过程

SQL> create or replace procedure test3.do_truncate ( ptablename in NVARCHAR2, poption in varchar2, pdebug in boolean default true )
  2  is
  3  vcount pls_integer;
  4  vsql varchar2(400);
  5  begin
  6   vsql := 'truncate table ' || ptablename || ' ' || poption || ' storage ';
  7   select count(*) into vcount from user_tables where table_name = upper(ptablename) ;
  8   if vcount = 1
  9   then
 10     if pdebug
 11     then
 12             dbms_output.put_line(vsql);
 13     end if;
 14     execute immediate vsql;
 15   else
 16     raise_application_error(-20001,'Table '||ptablename||' does not exist in schema TEST3 ');
 17   end if;
 18* end;

 Procedure created.

SQL> exec test3.do_truncate( 'T1' , 'REUSE' , true ) ;
truncate table T1 REUSE storage

PL/SQL procedure successfully completed.

SQL> exec test3.do_truncate( 'T2' , 'DROP' , true ) ;
BEGIN test3.do_truncate( 'T2' , 'DROP' , true ) ; END;

*
ERROR at line 1:
ORA-20001: Table T2 does not exist in schema TEST3
ORA-06512: at "TEST3.DO_TRUNCATE", line 16
ORA-06512: at line 1

如果您也想控制该选项

create or replace procedure test3.do_truncate ( ptablename in NVARCHAR2, poption in varchar2, pdebug in boolean default true )
 is
 vcount pls_integer;
 vsql varchar2(400);
 begin
  if upper(poption) not in ('DROP','REUSE') 
  then 
     raise_application_error(-20002,'Specify DROP or REUSE for storage option in truncate');
  end if;
  vsql := 'truncate table ' || ptablename || ' ' || poption || ' storage ';
  select count(*) into vcount from user_tables where table_name = upper(ptablename) ;
  if vcount = 1
  then
    if pdebug
    then
            dbms_output.put_line(vsql);
    end if;
    execute immediate vsql;
  else
    raise_application_error(-20001,'Table '||ptablename||' does not exist in schema TEST3 ');
  end if;
 end;

评论

  • 最好控制过程中的错误,以防截断它不存在的表。
  • 正如@MTO已经解释的那样,它本身不应该在程序中。如果您要删除/创建表,这将是必要的。GRANT
  • 您可以使用两个选项进行截断
    • reuse storage
    • drop storage

指定从已删除的行中取消分配所有空间 从表中,但 MINEXTENTS 参数分配的空间除外 表或集群。此空间随后可供其他空间使用 表空间中的对象。Oracle Database 还设置 NEXT 存储 参数设置为从线段中移除的最后一个范围的大小 截断过程。这是默认设置。DROP STORAGE

指定以保留已删除行的空间 分配给表。存储值不会重置为值 创建表或集群时。此空间随后可以 仅由表或集群中的新数据使用,这些数据由插入或 更新操作。此子句将存储参数保留在 当前设置。REUSE STORAGE