CREATE OR REPLACE FUNCTION sumNumbers(p VARCHAR2) RETURN NUMBER IS
...
SELECT sumNumbers('3 + 6 + 13 + 0 + 1') FROM dual;
所以输出应该是:23
PL/SQL用“+”分割一个字符串并对其中的数字求和?
CREATE OR REPLACE FUNCTION sumNumbers(p VARCHAR2) RETURN NUMBER IS
...
SELECT sumNumbers('3 + 6 + 13 + 0 + 1') FROM dual;
所以输出应该是:23
PL/SQL用“+”分割一个字符串并对其中的数字求和?
您可以使用一个 '窍门' 与XML和XPath评估要做到这一点,而无需手动tokenising字符串:
select * from xmltable('3 + 6 + 13 + 0 + 1' columns result number path '.');
RESULT
----------
23
或者:
select to_number(xmlquery('3 + 6 + 13 + 0 + 1' returning content).getStringVal()) as result
from dual;
RESULT
----------
23
这是作为其他运营商可以使用更灵活:
select * from xmltable('2 * (5 + 7) - 3' columns result number path '.');
RESULT
----------
21
使用正常/
运营商,虽然它不喜欢分裂,你需要使用div
代替,所以你可能需要做您的源字符串替换,如果它可能包含一个斜杠:
select * from xmltable('2 * (5 + 7) div 3' columns result number path '.');
RESULT
----------
8
阅读更多关于Oracle's XPath handling和。
你可以直接调用它,而不需要函数;但如果你特别想将其包装在一个函数这是一个稍微复杂的XPath的必须固定在分析时,那么你就需要使用动态SQL:
CREATE OR REPLACE FUNCTION sumNumbers(p VARCHAR2) RETURN NUMBER IS
l_result NUMBER;
BEGIN
execute immediate q'[select * from xmltable(']'
|| replace(p, '/', ' div ')
|| q'[' columns result number path '.')]'
into l_result;
return l_result;
END;
/
SELECT sumNumbers('3 + 6 + 13 + 0 + 1') FROM dual;
SUMNUMBERS('3+6+13+0+1')
---------------------------------------
23
我用the alternative quoting mechanism避免逃避声明中的单引号,尽管我不确定它在这里更清晰。并且我已经包含了replace()
以防需要分割,但它不需要那么直接将p
直接连接到SQL语句中。有了替代你可以这样做:
SELECT sumNumbers('2 * (5 + 7)/3') FROM dual;
如果你要允许其灵活的功能应该有不同的名称...
不错,从来没有想过(错) - 以这种方式使用XPath。 –
谢谢,但我应该如何实现你的代码到我的函数? – andrasb
@andrasb - 添加了一个使用XMLTable方法的函数。 –
您可以用层次查询和正则表达式中提取的数字,总结的结果。事情是这样的:
WITH t AS (
SELECT '3 + 6 + 13 + 0 + 1' numbers FROM DUAL
)
SELECT SUM(TRIM(REGEXP_SUBSTR(numbers,'(?[[:digit:]]+ ?)',1,LEVEL)))
FROM t
CONNECT BY LENGTH(SUBSTR(numbers,DECODE(REGEXP_INSTR(numbers,'(?[[:digit:]]+ ?)',1,LEVEL),0,NULL,REGEXP_INSTR(numbers,'(?[[:digit:]]+ ?)',1,LEVEL)))) <= LENGTH(SUBSTR(numbers,DECODE(REGEXP_INSTR(numbers,'(?[[:digit:]]+ ?)',1,LEVEL),0,NULL,REGEXP_INSTR(numbers,'(?[[:digit:]]+ ?)',1,LEVEL))));
如果你只是想试用的表达,为什么不”你只是 - 好 - 评估它?
FUNCTION sumNumbers(p VARCHAR2) RETURN NUMBER IS
l_result NUMBER;
BEGIN
EXECUTE IMMEDIATE 'begin :n := ' || p || '; end;'
USING OUT l_result;
RETURN l_result;
END;
我在答案的第一个版本中采用了类似的方法,但确定SQL注入风险并不明智。啊,但我选择了双重结果;这在某种程度上更好,但是你仍然可以用'p'来做一些令人讨厌的事情。你可以像'1;立即执行''drop table x''''例如? –
当然,我以为你对快速和肮脏的解决方案感兴趣。为了避免SQL注入,我建议首先验证表达式(例如使用正则表达式)。 Alex建议的xml技巧也应该是安全的 –
你是否一定要分裂它,或者你真的只是想要评估任何方式,你可以?它总是只有加号,还是可以有其他操作符,括号等?数字总是正整数吗? –