字符串中的值替换/替换

时间:2016-08-11 09:26:37

标签: sql oracle plsql

我有一个字符串x-y+z。 x,y和z的值将存储在表中。说

x 10
y 15
z 20

此字符串需要更改为10-15+20

无论如何,我可以用plsql或sql实现这个目的吗?

4 个答案:

答案 0 :(得分:0)

使用简单的Pivot我们可以做到

DECLARE @Table1 TABLE 
    ( name  varchar(1),  amount  int  )
;

INSERT INTO @Table1
    ( name ,  amount  )
VALUES
    ('x', 10),
    ('y', 15),
        ('Z', 25);

脚本

Select CAST([X] AS VARCHAR) +'-'+CAST([Y] AS VARCHAR)+'+'+CAST([Z] AS VARCHAR) from (
select * from @Table1)T
PIVOT (MAX(amount) FOR name in ([X],[y],[z]))p

答案 1 :(得分:0)

如果有这样的表格,可以采用以下方法:

create table stringToNumbers(str varchar2(16), num number);
insert into stringToNumbers values ('x', 10);
insert into stringToNumbers values ('y', 20);
insert into stringToNumbers values ('zz', 30);
insert into stringToNumbers values ('w', 40);

首先使用以下内容对输入字符串进行标记:

SQL> with test as (select 'x+y-zz+w' as string from dual)
  2  SELECT 'operand' as typ, level as lev, regexp_substr(string, '[+-]+', 1, level) as token
  3    FROM test
  4  CONNECT BY regexp_instr(string, '[a-z]+', 1, level+1) > 0
  5  UNION ALL
  6  SELECT 'value', level, regexp_substr(string, '[^+-]+', 1, level) as token
  7    FROM test
  8  CONNECT BY regexp_instr(string, '[+-]', 1, level - 1) > 0
  9  order by lev asc, typ desc;

TYP            LEV TOKEN
------- ---------- --------------------------------
value            1 x
operand          1 +
value            2 y
operand          2 -
value            3 zz
operand          3 +
value            4 w

在示例中,我使用了小写文字,只使用了+/-符号;你可以轻松编辑它来处理更复杂的事情;另外,我假设输入字符串格式正确。

然后,您可以将解码表加入标记化字符串,构建串联:

SQL> select listagg(nvl(to_char(num), token)) within group (order by lev asc, typ desc)
  2  from (
  3          with test as (select 'x+y-zz+w' as string from dual)
  4          SELECT 'operand' as typ, level as lev, regexp_substr(string, '[+-]+', 1, level) as token
  5            FROM test
  6          CONNECT BY regexp_instr(string, '[a-z]+', 1, level+1) > 0
  7          UNION ALL
  8          SELECT 'value', level, regexp_substr(string, '[^+-]+', 1, level) as token
  9            FROM test
 10          CONNECT BY regexp_instr(string, '[+-]', 1, level - 1) > 0
 11          order by lev asc, typ desc
 12       ) tokens
 13       LEFT OUTER JOIN stringToNumbers on (str = token);

LISTAGG(NVL(TO_CHAR(NUM),TOKEN))WITHINGROUP(ORDERBYLEVASC,TYPDESC)
--------------------------------------------------------------------------------
10+20-30+40

这假定您输入字符串中的每个文字都在表中具有相应的值。您甚至可以处理没有相应编号的字符串的情况,例如分配0:

SQL> select listagg(
  2                  case
  3                    when typ = 'operand' then token
  4                    else to_char(nvl(num, 0))
  5                  end
  6                ) within group (order by lev asc, typ desc)
  7  from (
  8          with test as (select 'x+y-zz+w-UNKNOWN' as string from dual)
  9          SELECT 
 ..          ...
 16       ) tokens
 17       LEFT OUTER JOIN stringToNumbers on (str = token);

LISTAGG(CASEWHENTYP='OPERAND'THENTOKENELSETO_CHAR(NVL(NUM,0))END)WITHINGROUP(ORD
--------------------------------------------------------------------------------
10+20-30+40-0

答案 2 :(得分:0)

创建一个这样的函数:

create table ttt1 
    ( name  varchar(1),  amount  int  )
;

INSERT INTO ttt1 VALUES ('x', 10);
INSERT INTO ttt1 VALUES ('y', 15);
INSERT INTO ttt1 VALUES ('z', 25);

CREATE OR REPLACE FUNCTION replace_vars (in_formula VARCHAR2)
   RETURN VARCHAR2
IS
   f   VARCHAR2 (2000) := UPPER (in_formula);
BEGIN
   FOR c1 IN (  SELECT UPPER (name) name, amount
                  FROM ttt1
              ORDER BY name DESC)
   LOOP
      f := REPLACE (f, c1.name, c1.amount);
   END LOOP;
   return f;
END;

select replace_vars('x-y+z') from dual

答案 3 :(得分:0)

这是解决尝试在SQL中完成所有操作的问题的另一种方法。虽然不一定是最灵活或最快的,但也许您可以从另一种方式获得一些想法来解决问题。它还显示了执行最终公式以获得答案的方法。请参阅以下评论。

假设变量表中存在所有变量。

-- First build the table that holds the values. You won't need to do 
--   this if you already have them in a table.
with val_tbl(x, y, z) as (
  select '10', '15', '20' from dual
),
-- Table to hold the formula.
formula_tbl(formula) as (
  select 'x-y+z' from dual
),
-- This table is built from a query that reads the formula a character at a time.  
--   When a variable is found using the case statement, it is queried in the value 
--   table and it's value is returned.  Otherwise the operator is returned.  This 
--   results in a row for each character in the formula.
new_formula_tbl(id, new_formula) as (
  select level, case regexp_substr(formula, '(.|$)', 1, level, NULL, 1)
         when 'x' then
         (select x from val_tbl)
         when 'y' then
         (select y from val_tbl)
         when 'z' then
         (select z from val_tbl)
         else regexp_substr(formula, '(.|$)', 1, level, NULL, 1)
         end
  from formula_tbl
  connect by level <= regexp_count(formula, '.')
)
-- select id, new_formula from new_formula_tbl;
-- This puts the rows back into a single string. Order by id (level) to keep operands
--   and operators in the right order.
select listagg(new_formula) within group (order by id) formula
from new_formula_tbl;

   FORMULA
----------
  10-15+20

此外,您可以通过将listagg()调用传递给以下xmlquery()函数来获取公式的结果:

select xmlquery(replace( listagg(new_formula) within group (order by id), '/', ' div ')
       returning content).getNumberVal() as result
from new_formula_tbl;

    RESULT
----------
        15