【发布时间】:2017-01-17 07:23:26
【问题描述】:
我有一个工作场所问题,我正在寻找一个简单的解决方案。 我正在尝试在较小的场景中复制它。
简单的问题
我想在in 子句中使用nvl。目前我有一个由名称组成的输入字符串。它用于下面的 where 子句中
and column_n = nvl(in_parameter,column_n)
现在我想在同一个输入参数中传递多个逗号分隔的值。因此,如果我将= 替换为in,并将输入的逗号分隔字符串转置为行,我将无法使用nvl 子句。
问题详解
让我们考虑一个 Employee 表 emp1。
Emp1
+-------+-------+
| empno | ename |
+-------+-------+
| 7839 | KING |
| 7698 | BLAKE |
| 7782 | CLARK |
+-------+-------+
现在这是现有存储过程的简单版本
create or replace procedure emp_poc(in_names IN varchar2)
as
cnt integer;
begin
select count(*)
into cnt
from emp1
where
ename = nvl(in_names,ename); --This is one of the condition where we will make the change.
dbms_output.put_line(cnt);
end;
所以这将给出作为输入参数传递的员工数量的计数。但是如果我们传递 null,它将返回员工总数,因为 nvl。
所以这些过程调用将呈现给定的输出。
Procedure Call Output
exec emp_poc('KING') 1
exec emp_poc('JOHN') 0
exec emp_poc(null) 3
现在我想要实现的是添加另一个功能。所以exec emp_poc('KING,BLAKE') 应该给我2。所以我想出了一种将逗号分隔的字符串拆分为行并在过程中使用的方法。
如果我将下面的where 子句更改为in
create or replace procedure emp_poc2(in_names IN varchar2)
as
cnt integer;
begin
select count(*)
into cnt
from emp1
where
ename in (select trim(regexp_substr(in_names, '[^,]+', 1, level))
from dual
connect by instr(in_names, ',', 1, level - 1) > 0
);
dbms_output.put_line(cnt);
end;
所以exec emp_poc2('KING','BLAKE') 给了我2。但是通过null 将得到0 的结果。但是我想得到3 就像emp_proc 的情况一样
而且我不能将nvl 与in 一起使用,因为它希望子查询返回单个值。
我能想到的一种方法是根据输入参数在变量中重建整个查询,然后使用execute immediate。但是我正在使用一些变量来收集值,而使用execute immediate 很难实现它。
我再次强调,这是一个复杂过程的简单版本,我们在其中捕获许多变量,它连接许多表,并且在 where 子句中有多个 AND 条件。
关于如何完成这项工作的任何想法。
【问题讨论】:
-
输入变量 (
in_names) 数据类型是字符串还是必须是集合/容器数据类型? -
这根本不是强制性的。无论哪种效果更好,我都可以使用它。
-
逗号分隔的列表在 SQL 或 PL/SQL 中并不像在其他一些语言中那样 - 它只是一个恰好包含逗号的文本字符串。没有内置方法可以将其视为文字列表或元素数组或其他任何东西。
-
@WilliamRobertson 你能说出一种语言,其中包含逗号的文本字符串不仅仅是一个文本字符串吗?还是我看错了你的评论?
-
我想到了 JavaScript 和 Bash。当然,它们并不完全将包含逗号的字符串变量视为数组,但它们以 SQL 没有的方式非常透明地转换它们。
标签: sql oracle plsql oracle11g