是否可以迭代字符串列表并使用 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