根据用户参数进入循环

Posted

技术标签:

【中文标题】根据用户参数进入循环【英文标题】:Enter the loop based on user parameter 【发布时间】:2012-10-31 12:33:40 【问题描述】:

有4个参数.material,Suppliernbr,Suppliername,Materail code。我的查询是如果用户在单个参数中输入任何具有单个值的参数,我需要进入循环。

For Eg:
P_suppname='stack'
p_matrl='NULL'
p_suppnbr:=NULL
P_mtrlcde='NULL' I can go inside 

但是如果

P_suppname=NULL
p_matrl=211
p_suppnbr:=43443443
P_mtrlcde='NULL' I shouldnt go.

还有

P_suppname=NULL
p_matrl='211;2322'
p_suppnbr:=NULL
P_mtrlcde='NULL' I should nt go

如何做到这一点??

【问题讨论】:

您发布的示例没有意义:'NULL' 与 NULL 相同吗?在第一个示例中,'NULL' 不算作一个值,但在第三个示例中它确实如此。或者你的意思是 '211;2322' 算作两个值?在我看来,您需要重新考虑您的界面。 【参考方案1】:

统计每个参数中;的个数,使用nvl对空值计数为零:

select 
  nvl( length('211;2322')    - length(replace('211;2322', ';', ''))    +1, 0), -->2
  nvl( length('211;2322;34') - length(replace('211;2322;34', ';', '')) +1, 0), -->3
  nvl( length(Null)          - length(replace(Null, ';', ''))          +1, 0)  -->0
from dual

IF条件中使用:

IF ( nvl( length(p_suppname) - length(replace(p_suppname, ';', '')) +1, 0)
   + nvl( length(p_matrl)    - length(replace(p_matrl, ';', ''))    +1, 0)
   + nvl( length(p_suppnbr)  - length(replace(p_suppnbr, ';', ''))  +1, 0)
   + nvl( length(p_mtrlcde)  - length(replace(p_mtrlcde, ';', ''))  +1, 0)
) = 1 THEN
  --LOOP
END IF;

【讨论】:

我认为这不太对。对于问题中给出的前两个示例,IF 语句的总和为零。 这将是错误的 select nvl(length('211') - length(replace('211', ';', '')) ,0), -->2 nvl( length( '211') - 长度(替换('211', ';', '')) ,0), -->3 nvl(长度('NULL') - 长度(替换('null', ';', '')) ,0), -->0 nvl( length(Null) - length(replace(Null, ',', '')) ,0) -->0 来自对偶 @Tobsey 你是对的,我确定了答案。但是,现在它将'NULL' 计为一个参数。这不难解决,但恐怕这样做解决方案会变得太不优雅且难以阅读。【参考方案2】:

对于显而易见的解决方案,有很多话要说。毕竟,大自然给了我们剪切和粘贴,而不是使用它?

IF NOT ( (P_suppname is NOT NULL and p_matrl is null and p_suppnbr is NULL and P_mtrlcde is NULL )
    or  (P_suppname is NULL and p_matrl is NOT NULL and p_suppnbr is NULL and P_mtrlcde is NULL )
    or  (P_suppname is NULL and p_matrl is NULL and p_suppnbr is NOT NULL and P_mtrlcde is NULL )
     or  (P_suppname is NULL and p_matrl is NULL and p_suppnbr is NULL and P_mtrlcde is NOT NULL ) )
THEN
     raise_application_error(-20000, 'wrong number of parameters');
ELSE
    .....

这具有表达其意图的巨大好处:它清楚地检查一个且只有一个参数包含一个值。其他解决方案可能更奇葩,但它们会阻碍人们了解他们正在尝试做的事情的能力。


当然,发布的代码引入了一些复杂性。该接口显然允许调用程序传递字符串“NULL”,而不仅仅是传递 NULL。此外,虽然p_matrl 似乎是一个数字,但它被定义为 varchar2,因此调用程序可以传递诸如 '211;2322' 之类的废话。

解决这些缺陷的正确方法是修复 API,使其不接受此类废话。这是界面设计者的特权,可以指定调用程序应遵守的合同。换句话说,如果调用程序传递“NULL”而不是 NULL,则拒绝它们的参数。将p_matrl 的数据类型更改为数字。

但是,一旦 API 被广泛使用并投入使用,处理垃圾的负担就落在了界面设计师的肩上。他们必须包括额外的验证代码。这就是规格不佳的代价。不幸的是,它通常不是由原始人承担的:设计者的罪过在维护者身上被访问。

无论如何,为了解决这些问题,我们需要声明局部变量并检查/传递参数值。例如:

if p_matrl = 'NULL'
then
     l_matrl := null;
else
    l_matrl := to_number(p_matrl);
end if;

对所有参数进行验证,并在上面的 IF 语句中使用适当的变量。

【讨论】:

【参考方案3】:

虽然我无法想象会产生这种要求的接口类型(或NULL'NULL' 的有效值),但我将如何处理它:

DECLARE 

    cnt NUMBER;

BEGIN

SELECT DECODE(p_suppname, 'NULL',0, DECODE(INSTR(p_suppname,';'),NULL,0,0,1,0)) + 
DECODE(p_matrl, 'NULL', 0, DECODE(INSTR(p_suppname,';'),NULL,0,0,1,0)) + 
DECODE(p_suppnbr, NULL, 0, 1) + 
DECODE(p_mtrlcde, 'NULL', 0, DECODE(INSTR(p_suppname,';'),NULL,0,0,1,0)) into cnt 
from dual;

IF cnt = 1 THEN
    LOOP
        /* do whatever here */
    END LOOP;
END IF;

END;

我假设 p_suppnbr 是一个数字,而所有其他都是字符串。 我还假设任何参数都可以为 NULL,并且字符串“NULL”等价于 NULL 值。 (我还隐含地假设任何带有分号的参数至少包含 2 个值)

【讨论】:

以上是关于根据用户参数进入循环的主要内容,如果未能解决你的问题,请参考以下文章

在自定义 WebAPi 中调用 Azure Speech API 时进入无限循环

让 VBA 循环遍历 Outlook 中的所有收件箱,包括共享收件箱

根据用户输入的字符数循环列表

mybatis框架,使用foreach实现复杂结果的查询--循环List集合方式

带有invokelater的文档监听器进入无限循环

Jmeter使用CSV Data Set Config参数化数据不重复的多次循环执行(实现多用户多次抽奖功能)