使用SQL从字符串中分隔值

时间:2016-02-15 11:49:04

标签: sql oracle oracle12c

我有这个要求,我们需要将字符串中的值与

的格式分开
{Feature1=Value1} | {Feature2=Value2} | .. | {FeatureN=ValueN}

{12345=Gold}|{12346=Silver}

所以需要从给定的srting中分离出特征和值。

要分离我使用的PIPE分隔值..

select * 
  from xmltable('r/c' passing xmltype('<r><c>' || replace('{12345=Gold}|{12346=Silver}','|','</c><c>') || '</c></r>')
columns new_str varchar2(30) path '.');

NEW_STR                    
------------------------------
{12345=Gold}                 
{12346=Silver}               

我正在编写一个PLSQL块,它使用上面的查询迭代每个管道的单独值。 我可以将这些值存储在PLSQL变量中。

现在另一个任务是从上面的两个字符串中获取特征和值,我在SQL

下面写
select substr ('{12345=Gold}',2, instr('{12345=Gold}', '=')-2) features from dual;

FEATURES
----------------------
12345

SELECT SUBSTR('{12345=Gold}', instr('{12345=Gold}', '=')+1, LENGTH(substr ('{12345=Gold}', instr('{12345=Gold}', '=')+1, INSTR('{12345=Gold}', '}', 2)))-1) value FROM DUAL;

VALUE
--------------
Gold

所以在这里我能够从字符串中获取特征和值......

我正在为我的SQL专门寻找另一个或替代SQL的最后一个我发现它复杂的功能使用所以如果您对上述场景有任何更好的想法,那么请发布!

请询问情景是否不清楚

我的数据库是 -

Oracle Database 12c企业版12.1.0.2.0版 - 64位生产

5 个答案:

答案 0 :(得分:2)

with line as (
      select '{12345=Gold}|{12346=Silver}|{12399=Copper}' str from dual)

select substr (parse, 2, instr(parse,'=')-2) as feature
      ,substr (parse, instr(parse,'=')+1, length(parse)-instr(parse,'=')-1 ) as value
from
   (select distinct regexp_substr(str, '[^|]+', 1, level) as parse
    from line
    connect by regexp_substr(str, '[^|]+', 1, level) is not null)

答案 1 :(得分:1)

这是一种使用类型的方法和一个名为apex_util的方便的内置包:

MST

现在您可以查询:

create type keyval_t is object (key varchar2(10), value varchar2(100));
/

create type keyval_tab_t is table of keyval_t;
/

create or replace package test_pkg is
   function keyval_tab (p_keyval_string varchar2) return keyval_tab_t;
end;
/

create or replace package body test_pkg is
   function keyval_tab (p_keyval_string varchar2) return keyval_tab_t
   is
      l_tab apex_application_global.vc_arr2;
      l_tab2 apex_application_global.vc_arr2;
      l_keyval_tab keyval_tab_t := keyval_tab_t();
      l_str long;
   begin
      -- Split string at pipe delimiters
      l_tab := apex_util.string_to_table (p_keyval_string, '|');
      -- For each {key=value} pair
      for i in 1..l_tab.count loop
         l_str := l_tab(i);

         -- Remove the {}
         l_str := ltrim (l_str, '{ ');
         l_str := rtrim (l_str, '} ');

         -- Split string into key and value
         l_tab2 := apex_util.string_to_table (l_str, '=');
         if l_tab2.count = 2 then
            l_keyval_tab.extend;
            l_keyval_tab(i) := keyval_t (l_tab2(1), l_tab2(2));
         else
            -- ?? invalid string
            null;
         end if;
      end loop;
      return l_keyval_tab;
   end;

end;
/

答案 2 :(得分:1)

使用此查询获取预期输出。对不起,如果有太多的替换功能。但这很容易。

/**
 * Open a new private SQLiteDatabase associated with this Context's
 * application package.  Create the database file if it doesn't exist.
 ...
 ...
 */
public abstract SQLiteDatabase openOrCreateDatabase(String name,
        int mode, CursorFactory factory);

答案 3 :(得分:0)

如果您已经将列分隔成行,那么使用REGEXP_REPLACE函数要做的工作非常简单。

考虑到你的cols现在是:

NEW_STR                    
--------------
{12345=Gold}                 
{12346=Silver}

您可以执行此sql将其转换为两个不同的列:

select regexp_replace( col, '\{(\d+)=\w+\}', '\1' ) as feature,
       regexp_replace( col, '\{\d+=(\w+)\}', '\1' ) as value
  from testTable

将其转换为视图,然后根据需要选择列:

create or replace view testView as
   select regexp_replace( col, '\{(\d+)=\w+\}', '\1' ) as feature,
          regexp_replace( col, '\{\d+=(\w+)\}', '\1' ) as value
     from testTable

然后就这样做:

select * from testView where feature = '12345'

或者

Select * from testView where value = 'Gold'

如果您想将要素值转换为数字,请使用该列上的to_number函数:

to_number(regexp_replace( col, '\{(\d+)=\w+\}', '\1' ))

请记住,为了做到这一点,你必须绝对确定它只是数字,否则你会有转换错误

答案 4 :(得分:0)

您还可以使用数据透视表和REGEXP_SUBSTR

with MyStrings as
 (select '{Feature1=Value1}|{Feature2=Value2}|{FeatureN=ValueN}' Str from dual
  union all
  select '{12345=Gold}|{12346=Silver}' from dual
  )
,pivot as (
  Select Rownum Pnum
  From dual
  Connect By Rownum <= 100   
  )
SELECT rownum rn
      ,REGEXP_SUBSTR (ms.Str,'[^|]+',1,pv.pnum) TXT
  FROM MyStrings ms
      ,pivot pv
where REGEXP_SUBSTR (ms.Str,'[^|]+',1,pv.pnum) is not null