是否可以迭代字符串列表并使用 SQL 或 PL/SQL 根据当前值有条件地查询 oracle 数据库 table?
Is it possible to iterate over a list of strings and conditionally query an oracle database table based on the current value using SQL or PL/SQL?
是否可以使用 SQL 或 PL/SQL 根据字符串列表中的当前值进行条件查询?如果有帮助,我正在使用 Oracle 数据库?
所需功能示例(伪代码):
for stringVal in ('string1', 'string2', 'string3'):
if (stringVal == 'string2'):
select * from SCHEMA.TABLE where CONDITION;
else:
select * from OTHER_SCHEMA.OTHER_TABLE where CONDITION;
可能吗?是的。例如:
SQL> declare
2 l_result number;
3 begin
4 for stringval in (select 'string1' col from dual union all
5 select 'string2' from dual union all
6 select 'string3' from dual
7 )
8 loop
9 if stringval.col = 'string2' then
10 select max(sal)
11 into l_result
12 from scott.emp;
13 else
14 select min(deptno)
15 into l_result
16 from mike.dept;
17 end if;
18 dbms_output.put_line('Stringval.col = ' || stringval.col || '; result = ' || l_result);
19 end loop;
20 end;
21 /
Stringval.col = string1; result = 10
Stringval.col = string2; result = 5000
Stringval.col = string3; result = 10
PL/SQL procedure successfully completed.
SQL>
但是请注意,
IF
属于 PL/SQL
SELECT
必须有它的 INTO
;我的示例很简单,returns 只是一个标量变量的单个值。根据您的实际查询 return,您可能无法做到这一点,但可以使用例如取而代之的是集合或引用游标
根据您使用的版本,您可以使用 SQL 宏来完成。这些从 19.6 或 19.7 开始可用。简单的例子,你明白了:
SQL> create or replace function what_shall_i_do(tab dbms_tf.table_t, col dbms_tf.columns_t)
2 return varchar2 SQL_Macro is
3 stmt clob := 'select ';
4 cnm clob;
5 begin
6 for i in 1 .. col.count loop
7 cnm := col(i);
8 stmt := stmt || cnm || ',';
9 end loop;
10
11 return rtrim(stmt, ',') || ' from tab';
12
13 end;
14
15* /
Function WHAT_SHALL_I_DO compiled
SQL> select * from what_shall_i_do(dual, columns(dummy));
2*
DUMMY
________
X
SQL> select * from what_shall_i_do(sh.customers, columns(cust_id)) fetch first 5 rows only;
2*
CUST_ID
__________
49671
3228
6783
10338
13894
SQL>
如果条件不依赖于输入数据并且结果集包含相同的列,那么您可以使用由 union
组成的简单视图作为附加列并按该列进行过滤。优化器很聪明,可以找出并避免访问过滤掉的对象(参见 starts
列)。
create view v_test as
select
'table_1' as src, t1.*
from t1
where val = 3
union all
select 'table_2', t2.*
from t2
where id < 10
select /*+gather_plan_statistics*/ *
from v_test
where src = 'table_1'
SRC | ID | VAL | STR
:------ | -: | --: | :---------
table_1 | 3 | 3 | KJVK9GPV5D
table_1 | 8 | 3 | 5VQT72ICVR
table_1 | 13 | 3 | 7YIYAMOAA7
table_1 | 18 | 3 | NXGVIP1CFX
select *
from table(dbms_xplan.display_cursor(format => 'TYPICAL ALLSTATS LAST'))
| PLAN_TABLE_OUTPUT |
| :--------------------------------------------------------------------------------------------------------------------------------- |
| SQL_ID bfc7qqct9vamf, child number 0 |
| ------------------------------------- |
| select /*+gather_plan_statistics*/ * from v_test where src = 'table_1' |
| |
| Plan hash value: 2711242194 |
| |
| ---------------------------------------------------------------------------------------------------------------------------------- |
| | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | Reads | |
| ---------------------------------------------------------------------------------------------------------------------------------- |
| | 0 | SELECT STATEMENT | | 1 | | | 3 (100)| | 4 |00:00:00.01 | 2 | 1 | |
| | 1 | VIEW | V_TEST | 1 | 5 | 10185 | 3 (0)| 00:00:01 | 4 |00:00:00.01 | 2 | 1 | |
| | 2 | UNION-ALL | | 1 | | | | | 4 |00:00:00.01 | 2 | 1 | |
| |* 3 | TABLE ACCESS FULL | T1 | 1 | 4 | 68 | 3 (0)| 00:00:01 | 4 |00:00:00.01 | 2 | 1 | |
| |* 4 | FILTER | | 1 | | | | | 0 |00:00:00.01 | 0 | 0 | |
| |* 5 | TABLE ACCESS FULL| T2 | 0 | 10 | 220 | 3 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 0 | |
| ---------------------------------------------------------------------------------------------------------------------------------- |
| |
| Predicate Information (identified by operation id): |
| --------------------------------------------------- |
| |
| 3 - filter("VAL"=3) |
| 4 - filter(NULL IS NOT NULL) |
| 5 - filter("ID"<10) |
| |
db<>fiddle here
如果条件是动态的并且取决于输入数据,那么我将选择另一个答案中发布的现代 SQL Macro。
是否可以使用 SQL 或 PL/SQL 根据字符串列表中的当前值进行条件查询?如果有帮助,我正在使用 Oracle 数据库?
所需功能示例(伪代码):
for stringVal in ('string1', 'string2', 'string3'):
if (stringVal == 'string2'):
select * from SCHEMA.TABLE where CONDITION;
else:
select * from OTHER_SCHEMA.OTHER_TABLE where CONDITION;
可能吗?是的。例如:
SQL> declare
2 l_result number;
3 begin
4 for stringval in (select 'string1' col from dual union all
5 select 'string2' from dual union all
6 select 'string3' from dual
7 )
8 loop
9 if stringval.col = 'string2' then
10 select max(sal)
11 into l_result
12 from scott.emp;
13 else
14 select min(deptno)
15 into l_result
16 from mike.dept;
17 end if;
18 dbms_output.put_line('Stringval.col = ' || stringval.col || '; result = ' || l_result);
19 end loop;
20 end;
21 /
Stringval.col = string1; result = 10
Stringval.col = string2; result = 5000
Stringval.col = string3; result = 10
PL/SQL procedure successfully completed.
SQL>
但是请注意,
IF
属于 PL/SQLSELECT
必须有它的INTO
;我的示例很简单,returns 只是一个标量变量的单个值。根据您的实际查询 return,您可能无法做到这一点,但可以使用例如取而代之的是集合或引用游标
根据您使用的版本,您可以使用 SQL 宏来完成。这些从 19.6 或 19.7 开始可用。简单的例子,你明白了:
SQL> create or replace function what_shall_i_do(tab dbms_tf.table_t, col dbms_tf.columns_t)
2 return varchar2 SQL_Macro is
3 stmt clob := 'select ';
4 cnm clob;
5 begin
6 for i in 1 .. col.count loop
7 cnm := col(i);
8 stmt := stmt || cnm || ',';
9 end loop;
10
11 return rtrim(stmt, ',') || ' from tab';
12
13 end;
14
15* /
Function WHAT_SHALL_I_DO compiled
SQL> select * from what_shall_i_do(dual, columns(dummy));
2*
DUMMY
________
X
SQL> select * from what_shall_i_do(sh.customers, columns(cust_id)) fetch first 5 rows only;
2*
CUST_ID
__________
49671
3228
6783
10338
13894
SQL>
如果条件不依赖于输入数据并且结果集包含相同的列,那么您可以使用由 union
组成的简单视图作为附加列并按该列进行过滤。优化器很聪明,可以找出并避免访问过滤掉的对象(参见 starts
列)。
create view v_test as select 'table_1' as src, t1.* from t1 where val = 3 union all select 'table_2', t2.* from t2 where id < 10
select /*+gather_plan_statistics*/ * from v_test where src = 'table_1'
SRC | ID | VAL | STR :------ | -: | --: | :--------- table_1 | 3 | 3 | KJVK9GPV5D table_1 | 8 | 3 | 5VQT72ICVR table_1 | 13 | 3 | 7YIYAMOAA7 table_1 | 18 | 3 | NXGVIP1CFX
select * from table(dbms_xplan.display_cursor(format => 'TYPICAL ALLSTATS LAST'))
| PLAN_TABLE_OUTPUT | | :--------------------------------------------------------------------------------------------------------------------------------- | | SQL_ID bfc7qqct9vamf, child number 0 | | ------------------------------------- | | select /*+gather_plan_statistics*/ * from v_test where src = 'table_1' | | | | Plan hash value: 2711242194 | | | | ---------------------------------------------------------------------------------------------------------------------------------- | | | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | Reads | | | ---------------------------------------------------------------------------------------------------------------------------------- | | | 0 | SELECT STATEMENT | | 1 | | | 3 (100)| | 4 |00:00:00.01 | 2 | 1 | | | | 1 | VIEW | V_TEST | 1 | 5 | 10185 | 3 (0)| 00:00:01 | 4 |00:00:00.01 | 2 | 1 | | | | 2 | UNION-ALL | | 1 | | | | | 4 |00:00:00.01 | 2 | 1 | | | |* 3 | TABLE ACCESS FULL | T1 | 1 | 4 | 68 | 3 (0)| 00:00:01 | 4 |00:00:00.01 | 2 | 1 | | | |* 4 | FILTER | | 1 | | | | | 0 |00:00:00.01 | 0 | 0 | | | |* 5 | TABLE ACCESS FULL| T2 | 0 | 10 | 220 | 3 (0)| 00:00:01 | 0 |00:00:00.01 | 0 | 0 | | | ---------------------------------------------------------------------------------------------------------------------------------- | | | | Predicate Information (identified by operation id): | | --------------------------------------------------- | | | | 3 - filter("VAL"=3) | | 4 - filter(NULL IS NOT NULL) | | 5 - filter("ID"<10) | | |
db<>fiddle here
如果条件是动态的并且取决于输入数据,那么我将选择另一个答案中发布的现代 SQL Macro。