为啥没有在动态 SQL 中评估数学条件?

Posted

技术标签:

【中文标题】为啥没有在动态 SQL 中评估数学条件?【英文标题】:Why is a mathematical condition not being evaluated in dynamic SQL?为什么没有在动态 SQL 中评估数学条件? 【发布时间】:2015-11-02 09:33:48 【问题描述】:

我尝试了以下脚本来检查条件并产生布尔结果。但是,如果我给出任何数学函数,它就不起作用并且不显示值。

declare
     l_sql       varchar2(4000);
     l_condition varchar2(4000);
     ignore      pls_integer;
     l_cursor    number;
     l_names     dbms_sql.varchar2_table;     
begin
   for i in 1..2 loop     
       if i = 1 then
           l_condition := 'sysdate > to_date(''1/1/2007'',''mm/dd/yyyy'')';
       else
           l_condition := ':P1_ITEM = ' 'foo' '';
       end if;

       l_cursor := dbms_sql.open_cursor;
       l_sql := 'begin wwv_flow.g_boolean := '||l_condition||'; end;';
       l_names := wwv_flow_utilities.get_binds(l_sql);
       dbms_sql.parse(l_cursor,l_sql,dbms_sql.NATIVE);

       for i in 1 .. l_names.count loop
           dbms_sql.bind_variable( l_cursor, l_names(i), v( substr(l_names(i),2) ), 32000 );
       end loop;

       ignore := dbms_sql.execute(l_cursor);
       dbms_sql.close_cursor( l_cursor );

       if wwv_flow.g_boolean then
           dbms_output.put_line(l_condition||' is true.');
       else
           dbms_output.put_line(l_condition||' is false.');
       end if;       
   end loop;
end;

我正在尝试使用l_condition:= (5 > 3 AND 40 > 50) OR 10 进行评估。为什么它不起作用?

【问题讨论】:

你的代码失败的数学函数是什么? 你可以添加这个wwv_flow_utilities 吗? 我只是在 l_condition:= (5 > 3 AND 40 > 50) OR 10 中尝试了一个方程 但是没有解决方案或返回值......我不知道是否有任何函数计算值或返回公式的值......请帮我这样做 你有服务器输出,你没有看到真/假,你没有得到任何异常?该条件无效“或 10”不正确。大概你实际上把它作为一个字符串赋值,或者你会从中得到 PLS-00382。 (问题中的 FOO 检查看起来也不正确,但可能已更改为隐藏某些内容?) 【参考方案1】:

在 cmets 中,您曾说过您正在尝试“求解数学值 (5 > 3 AND 40 > 50) OR 10”,但这不是数学函数或有效的布尔逻辑。如果您确实进行了评估,那么5 > 3 为真,40 > 50 为假,并且到目前为止,将它们组合在一起是有效的;但是随后您尝试将结果与数字 10 进行或运算,而不是另一个布尔表达式。所以你在做:

(TRUE AND FALSE) OR 10

如果将其插入代码中,则会引发异常;您已将您的作业显示为:

l_condition:= (5 > 3 AND 40 > 50) OR 10 

这会给你一个简单的PLS-00382: expression is of wrong type 从块中的分配。如果你引用它,你会从动态 SQL 中得到同样的错误(删除不相关的绑定):

create package wwv_flow as
  g_boolean boolean;
end wwv_flow;
/

declare
     l_sql       varchar2(4000);
     l_condition varchar2(4000);
     ignore      pls_integer;
     l_cursor    number;
     l_names     dbms_sql.varchar2_table;     
     g_boolean boolean;
begin
   for i in 1..2 loop     
       if i = 1 then
           l_condition := 'sysdate > to_date(''1/1/2007'',''mm/dd/yyyy'')';
       else
--           l_condition := ':P1_ITEM = ' 'foo' '';
           l_condition:= '(5 > 3 AND 40 > 50) OR 10';
       end if;

       l_cursor := dbms_sql.open_cursor;
       l_sql := 'begin wwv_flow.g_boolean := '||l_condition||'; end;';
--       l_names := wwv_flow_utilities.get_binds(l_sql);
       dbms_sql.parse(l_cursor,l_sql,dbms_sql.NATIVE);

--       for i in 1 .. l_names.count loop
--           dbms_sql.bind_variable( l_cursor, l_names(i), v( substr(l_names(i),2) ), 32000 );
--       end loop;

       ignore := dbms_sql.execute(l_cursor);
       dbms_sql.close_cursor( l_cursor );

       if wwv_flow.g_boolean then
           dbms_output.put_line(l_condition||' is true.');
       else
           dbms_output.put_line(l_condition||' is false.');
       end if;       
   end loop;
end;
/

ORA-06550: line 1, column 52:
PLS-00382: expression is of wrong type
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
ORA-06512: at "SYS.DBMS_SQL", line 1199
ORA-06512: at line 20

如果您删除“OR 10”部分,那么它可以工作:

declare
...
           l_condition:= '(5 > 3 AND 40 > 50)';
...
end;
/

PL/SQL procedure successfully completed.

sysdate > to_date('1/1/2007','mm/dd/yyyy') is true.
(5 > 3 AND 40 > 50) is false.

所以问题不在于您的代码不起作用,而在于您的条件无效。如果您从另一个抑制异常的块(例如when others 异常处理程序)中运行它,或者您的客户端或任何调用它的东西没有报告异常,您需要找出原因并修复它。

【讨论】:

以上是关于为啥没有在动态 SQL 中评估数学条件?的主要内容,如果未能解决你的问题,请参考以下文章

为啥空的 JavaScript 数组在条件结构中评估为真?

当 lhs 为假时,为啥在逻辑 AND 中评估条件(三元)运算符

为啥即使我有评估数据的条件,打字稿也会抱怨类型?

有条件地评估条件 SQL

如何将学生和评估表连接到一个视图中?

case-when oracle sql的动态评估