Oracle 中的动态 select

Dynamic select in Oracle

我想做这样的事情:

sql_str := 'select ';    
if (user_input = 1) then
    sql_str := sql_str || 'a.col1 from tb1 a';
else
    sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';

execute sql_str

我对 Oracle 的过程、函数等没有太多经验,更不用说任何经验了

我无法找到如何在 Oracle 中创建过程(或函数)来执行上述代码。

感谢任何帮助。谢谢。

使用您的示例,这是实现动态的一种方法 SQL

正如其他人指出的那样,Stack Exchange 上有很多动态 sql 的例子。

关于这个 subject 的文档非常好。我喜欢 using 子句,它使动态 sql 更具可扩展性。

在实践中,动态 sql 做了一些事情:select ... 进入程序调用,dml,dcl。

SCOTT@dev>declare
  2  user_input number(1) :=1;
  3  sql_str varchar2(1000);
  4  begin
  5  
  6  sql_str := 'select ';    
  7  if (user_input = 1) then
  8  --    sql_str := sql_str || 'a.col1 from tb1 a';
  9      sql_str := sql_str || '''1'' from dual';
 10      dbms_output.put_line(sql_str);
 11  else
 12  --    sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
 13      sql_str := sql_str || '''2'' from dual';
 14      dbms_output.put_line(sql_str);
 15  end if;
 16  execute immediate sql_str;
 17  end;
 18  /
select '1' from dual

PL/SQL procedure successfully completed.

SCOTT@dev>declare
  2  user_input number(1) :=2;
  3  sql_str varchar2(1000);
  4  begin
  5  
  6  sql_str := 'select ';    
  7  if (user_input = 1) then
  8  --    sql_str := sql_str || 'a.col1 from tb1 a';
  9      sql_str := sql_str || '''1'' from dual';
 10      dbms_output.put_line(sql_str);
 11  else
 12  --    sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
 13      sql_str := sql_str || '''2'' from dual';
 14      dbms_output.put_line(sql_str);
 15  end if;
 16  execute immediate sql_str;
 17  end;
 18  /
select '2' from dual

PL/SQL procedure successfully completed.

以我的例子为例,正如人们评论的那样,一个简单的 select 语句通常没有意义(实际上没有人这样做)。

通过查看 v$sql 可以看到我的动态 sql 已被解析,其中显示了共享 sql 区域的统计信息:

APPS@dev>SELECT
      2      sql_id
      3  FROM
      4      v$sql
      5  WHERE
      6          1 = 1
      7      AND (
      8              sql_text = 'select ''1'' from dual'
      9          OR
     10              sql_text = 'select ''2'' from dual'
     11      ) AND
     12          parsing_schema_name = 'SCOTT';
    SQL_ID         
    -------------
    27q1fj58cnz0k  
    c9bw73fh2ay8d

基于评论的附录

正如 Alex 引用的那样,文档表明没有 into 子句的 select 语句不会被执行。至少解析出来了,可以在共享sql区看到,v$sql.

这是我使用 into 子句的示例。

APPS@dev>DECLARE
  2      user_input   NUMBER(1) := 1;
  3      sql_str      VARCHAR2(1000);
  4      v_val        VARCHAR2(1);
  5  BEGIN
  6      sql_str := 'select ';
  7      IF
  8          ( user_input = 1 )
  9      THEN
 10  --    sql_str := sql_str || 'a.col1 from tb1 a';
 11          sql_str := sql_str || '''1'' from dual';
 12      ELSE
 13  --    sql_str := sql_str || 'a.col1,b.col2,b.col3 from tb1 a,tb2 b';
 14          sql_str := sql_str || '''2'' from dual';
 15      END IF;
 16  
 17      EXECUTE IMMEDIATE sql_str INTO
 18          v_val;
 19      dbms_output.put_line(sql_str || ' => ' || v_val);
 20  END;
 21  /
select '1' from dual => 1


PL/SQL procedure successfully completed.

由于您没有返回任何值,我们必须进行处理。虽然用例不明确。

CREATE PROCEDURE dyn_sql_query (user_input IN NUMBER)
    IS
       sql_str VARCHAR2 (500) := 'SELECT ';
    BEGIN
       IF (user_input = 1) 
       THEN sql_str := sql_str || 'a.col1 from tb1 a';
       ELSE sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
       END IF;
       EXECUTE IMMEDIATE sql_query;
    END;

这是非常基本的函数脚本(注意 RETURN),它接受 table 名称和 returns 行数。

 CREATE FUNCTION count_rows (table_name IN VARCHAR2)
       RETURN PLS_INTEGER   // 
    IS
       sql_query VARCHAR2 (500) := 'SELECT COUNT(*) FROM ' || table_name;
       ret_val PLS_INTEGER;
    BEGIN
       EXECUTE IMMEDIATE sql_query INTO ret_val;
       RETURN ret_val;
    END;

我不确定它是否对你有帮助,但你可以创建一个类似于下面的过程

CREATE OR REPLACE PROCEDURE test_Ali (user_input IN VARCHAR2(2))
IS
   sql_str      VARCHAR2(1000):= 'select ';
   user_input   VARCHAR2(2) := '1';

BEGIN

IF  user_input = '1' THEN 

BEGIN

sql_str := sql_str||'a.col1 from tb1 a';

EXECUTE IMMEDIATE sql_str;

dbms_output.put_line (sql_str) ;
END;

ELSE

BEGIN

sql_str := sql_str||'a.col1, b.col2, b.col3 from tb1 a, tb2 b';

EXECUTE IMMEDIATE sql_str;

dbms_output.put_line (sql_str) ;
END;

END IF;

END;