PL / SQL用“+”分割字符串并将其中的数字相加?

时间:2016-04-27 08:34:58

标签: sql oracle plsql

CREATE OR REPLACE FUNCTION sumNumbers(p VARCHAR2) RETURN NUMBER IS

...

SELECT sumNumbers('3 + 6 + 13 + 0 + 1') FROM dual;

所以输出应该是:23

3 个答案:

答案 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 handlingXPath 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;