Oracle中的动态选择

时间:2017-07-24 15:28:28

标签: oracle plsql dynamic-sql

我想做这样的事情:

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中创建过程(或函数)来执行上述代码。

感谢任何帮助。谢谢。

3 个答案:

答案 0 :(得分:1)

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

正如其他人所说,Stack Exchange上有很多动态sql的例子。

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

在实践中,动态sql做了一些事情:select ... into,一个程序调用,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语句通常没有意义(在实践中没有人这样做)。

可以看到我的动态sql是通过查看显示共享sql区域的统计信息的v$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.

答案 1 :(得分:1)

由于您没有返回任何价值,我们必须去寻找程序。虽然用例不明确。

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)的非常基本的脚本,它接受表名并返回行数。

 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;

答案 2 :(得分:1)

我不确定它是否对您有所帮助,但您可以创建类似下面的程序

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;