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

Posted

技术标签:

【中文标题】Oracle 的 EXECUTE IMMEDIATE 与存储过程中的 LIKE 子句【英文标题】:Oracle's EXECUTE IMMEDIATE with LIKE clauses in a stored procedure 【发布时间】:2020-09-07 11:52:25 【问题描述】:

我正在尝试编写一个基于模式名称和表名称参数返回序列名称的过程。

该过程将查看all_sequences 并根据给定的模式和表名找到正确的序列。它将通过 EXECUTE IMMEDIATE 命令执行此操作,并将序列名称插入到变量中。

所有序列都命名为s_[table_name]seq_[table_name][table_name]_seq

这是我写的代码:

    PROCEDURE proc_find_sequence(  
                            shema_name VARCHAR2,
                            table_name VARCHAR2,
                        ) 
  IS
    
    sequence_name1      VARCHAR2(30);    
    
  BEGIN
  
    
  EXECUTE IMMEDIATE 
  'SELECT s.sequence_name FROM all_sequences s 
   WHERE 
    s.SEQUENCE_OWNER = UPPER('||shema_name||')
  AND
  (
    s.sequence_name LIKE UPPER(''''S_%'''||table_name||')
    OR 
    s.sequence_name LIKE UPPER(''''SEQ_%'''||table_name||')
    OR
    s.sequence_name LIKE UPPER('||table_name||'''%_SEQ'''')
    )'
     INTO sequence_name1;
   
   
    DBMS_OUTPUT.PUT_LINE(sequence_name1); 

END;

我得到的错误是“ORA-00907:缺少右括号”,尽管我确信问题在于我使用括号之间的参数实现 LIKE 子句的方式。

对于如何解决问题的任何帮助或想法都将不胜感激。

【问题讨论】:

为什么要使用动态 SQL? 【参考方案1】:

您不需要动态 SQL。只需使用这个:

SELECT s.sequence_name 
FROM all_sequences s 
INTO sequence_name1
WHERE 
    s.SEQUENCE_OWNER = UPPER(shema_name)
  AND
  (
    s.sequence_name = UPPER('S_'||table_name)
    OR 
    s.sequence_name = UPPER('SEQ_'||table_name)
    OR
    s.sequence_name = UPPER(table_name||'_SEQ')
  )

或者只是

s.sequence_name IN (
    UPPER('S_'||table_name), 
    UPPER('SEQ_'||table_name), 
    UPPER(table_name||'_SEQ'))

正则表达式也应该可以工作

REGEXP_LIKE(s.sequence_name, '^S(EQ)?_'||table_name||'$', 'i')
   or REGEXP_LIKE(s.sequence_name, '^'||table_name||'_SEQ$', 'i')

【讨论】:

除了来自@Wernfried Domscheit 的回答之外,您不需要一个过程,而是一个返回类型为varchar2 的函数,而且您可能会得到两个结果您需要使用too_many_rows 处理错误并返回一些文本,例如More than one sequence found 或任何需要的内容。【参考方案2】:

如果你坚持使用 PL/SQL,我相信你不需要它(正如@Wemfried 提供的答案),你可以试试这个。考虑

-您自己说序列只能采用s_[table_name]seq_[table_name][table_name]_seq 中的一个。

-因此,您可以使用单个like 表达式,如S%TABLE_NAME%,它涵盖了所有场景。

set serveroutput on echo on
declare
shema_name varchar2(40)  := 'SYS' ;
table_name  varchar2(128) := 'MY_TABLE' ;
begin
dbms_output.put_line ( 'SELECT s.sequence_name FROM all_sequences s  
      where
      s.SEQUENCE_OWNER = UPPER('''||shema_name||''')
      AND
       s.sequence_name like UPPER(''%'||table_name||'%'')
       ' );
end;
/

如果我执行这个:

SQL> create table my_table ( c1 number ) ;

Table created.

SQL> create sequence s_my_table start with 1 increment by 1 ;

Sequence created.

SQL> set serveroutput on echo on
declare
shema_name varchar2(40)  := 'SYS' ;
table_name  varchar2(128) := 'MY_TABLE' ;
begin
dbms_output.put_line ( 'SELECT s.sequence_name FROM all_sequences s
      where
      s.SEQUENCE_OWNER = UPPER('''||shema_name||''')
      AND
       s.sequence_name like UPPER(''%'||table_name||'%'')
       ' );
end;
/
  SELECT s.sequence_name FROM all_sequences s
  where
  s.SEQUENCE_OWNER = UPPER('SYS')
  AND
   s.sequence_name like UPPER('%MY_TABLE%')


 PL/SQL procedure successfully completed.

SQL> SELECT s.sequence_name FROM all_sequences s
      where
      s.SEQUENCE_OWNER = UPPER('SYS')
      AND
       s.sequence_name like UPPER('%MY_TABLE%')
  ;

SEQUENCE_NAME
--------------------------------------------------------------------------------------------------------------------------------
S_MY_TABLE

【讨论】:

【参考方案3】:

另一种看法,不是关于您的代码有什么问题,而是关于在处理此类问题时如何自己找到问题。

您不应将查询构造为 EXECUTE IMMEDIATE 语句的一部分,而应将其分配给一个变量。然后出于调试目的,显示您构建的内容。然后你可以通过引用变量来实际执行它:

    PROCEDURE proc_find_sequence(  
                            shema_name VARCHAR2,
                            table_name VARCHAR2,
                        ) 
  IS
    
    sequence_name1      VARCHAR2(30); 
    v_sql               varchar2(2048);   
    
  BEGIN
  
    
  v_sql := 
  'SELECT s.sequence_name FROM all_sequences s 
   WHERE 
    s.SEQUENCE_OWNER = UPPER('||shema_name||')
  AND
  (
    s.sequence_name LIKE UPPER(''''S_%'''||table_name||')
    OR 
    s.sequence_name LIKE UPPER(''''SEQ_%'''||table_name||')
    OR
    s.sequence_name LIKE UPPER('||table_name||'''%_SEQ'''')
    )'
     INTO sequence_name1;
   
  dbms_output_put_line(v_sql);
  execute immediate v_sql;
   
    DBMS_OUTPUT.PUT_LINE(sequence_name1); 

END;

【讨论】:

以上是关于Oracle 的 EXECUTE IMMEDIATE 与存储过程中的 LIKE 子句的主要内容,如果未能解决你的问题,请参考以下文章

Oracle中Execute Immediate用法

ORACLE EXECUTE IMMEDIATE 小结

Oracle中动态SQL详解(EXECUTE IMMEDIATE)

oracle 中execute immediate作用

oracle表单如何在execute_query之后保持复选框被选中

mariadb 10.2.3支持oracle execute immediate语法