CREATE OR REPLACE FUNCTION sumNumbers(p VARCHAR2) RETURN NUMBER IS
...
SELECT sumNumbers('3 + 6 + 13 + 0 + 1') FROM dual;
所以输出应该是:23
答案 0 :(得分:8)
您可以使用带有XML和XPath评估的'技巧'来执行此操作,而无需手动标记字符串:
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 numeric operators。
你可以直接调用它,没有函数;但是如果你特别想把它包装在一个函数中,那么因为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;
如果你想让它变得灵活,那么这个功能应该有一个不同的名字......
答案 1 :(得分:1)
您可以使用分层查询和正则表达式提取数字并对结果求和。像这样:
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))));
答案 2 :(得分:0)
如果您只想评估表达方式,为什么不这样做 - 好吧 - 评估一下?
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;