找到收集数据并替换另一个表中的值的方法

时间:2017-06-06 13:51:44

标签: sql oracle

我正在寻找一个Oracle SQL查询来查找特定模式,并将其替换为另一个表中的值。

情景:

表1:

No      column1
-----------------------------------------
12345  user:12345;group:56789;group:6785;...

注意:字段1可能有一个或多个模式

表2:

Id     name       type
----------------------
12345  admin      user
56789  testgroup  group

结果必须相同

No        column1
-----------------------------------
12345     user: admin;group:testgroup

2 个答案:

答案 0 :(得分:0)

<强>逻辑:

  • 首先使用connect by子句和正则表达式将连接的字符串拆分为各行。
  • 使用Table2(tab2)加入新创建的表(split_tab)。
  • 使用listagg函数连接列中的数据。

<强>查询:

WITH tab1 AS
     ( SELECT '12345' NO
             ,'user:12345;group:56789;group:6785;' column1
        FROM DUAL )
    ,tab2 AS
     ( SELECT 12345 id
             ,'admin' name
             ,'user' TYPE
        FROM DUAL
      UNION
      SELECT 56789 id
            ,'testgroup' name
            ,'group' TYPE
        FROM DUAL )
SELECT no
      ,listagg(category||':'||name,';') WITHIN GROUP (ORDER BY tab2.id) column1
  FROM ( SELECT    NO
                  ,REGEXP_SUBSTR( column1, '(\d+)', 1, LEVEL ) id
                  ,REGEXP_SUBSTR( column1, '([a-z]+)', 1, LEVEL ) CATEGORY
              FROM tab1
        CONNECT BY LEVEL <= regexp_count( column1, '\d+' ) ) split_tab
      ,tab2
 WHERE split_tab.id = tab2.id
 GROUP BY no

输出

No     Column1
12345  user:admin;group:testgroup

答案 1 :(得分:0)

with t1 (no, col) as 
(
  -- start of test data
  select 1,   'user:12345;group:56789;group:6785;' from dual union all
  select 2,   'user:12345;group:56789;group:6785;' from dual
  -- end of test data
)
  -- the lookup table which has the substitute strings
  -- nid : concatenation of name and id as in table t1 which requires the lookup
  -- tname : required substitute for each nid
, t2 (id, name, type, nid, tname) as
(

  select t.*, type || ':' || id, type || ':' || name from 
  (
    select 12345 id,  'admin' name,      'user' type from dual union all
    select 56789,  'testgroup',  'group' from dual 
  ) t
)
--select * from t2; 
-- cte table calculates the indexes for the substrings (eg, user:12345)
-- no : sequence no in t1
-- col : the input string in t1
-- si : starting index of each substring in the 'col' input string that needs attention later
-- ei : ending index of each substring in the 'col' input string
-- idx : the order of substring to put them together later
,cte (no, col, si, ei, idx) as
(
  select no, col, 1, case when instr(col,';') = 0 then length(col)+1 else instr(col,';') end, 1 from t1 union all
  select no, col, ei+1, case when instr(col,';', ei+1) = 0 then length(col)+1 else instr(col,';', ei+1)  end, idx+1 from cte where ei + 1 <= length(col)
)
,coll(no, col, sstr, idx, newstr) as
(
  select 
    a.no, a.col, a.sstr, a.idx, 
    -- when a substitute is not found in t2, use the same input substring (eg. group:6785)
    case when t2.tname is null then a.sstr else t2.tname end 
  from 
    (select cte.*, substr(col, si, ei-si) as sstr from cte) a 
    -- we don't want to miss if there is no substitute available in t2 for a substring
    left outer join 
    t2 
    on (a.sstr = t2.nid)
)
select no, col, listagg(newstr, ';') within group (order by no, col, idx) from coll
group by no, col;