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;
我想做这样的事情:
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;