2017-06-06 1 views
0

特定のパターンを見つけて別のテーブルの値で置き換えるOracle SQLクエリを探しています。データを収集し、別のテーブルの値で置き換える方法を見つける

シナリオ:

表1:

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

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

結果は同じ

でなければなりません。フィールド1は、1つまたは複数のパターンを有する

表2であってもよいです

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

なぜPLSQL?プレーンなSQLクエリは良いですか?また、これまでに何を試しましたか? – Aleksej

+0

私のdbはOracleであり、私はそれらを操作するだけです – user3728800

+1

PLSQLはSQLのOracle手続き型拡張です。 Oracle用にSQLクエリが必要な場合は、PLSQLではなく、OracleとSQLにタグを付けるほうがよいでしょう。また、これまでに試したものや投稿したものを投稿してください。 – Aleksej

答えて

0

ロジック:

  • まずconnect by句と正規表現を使用して、個々の行に連結された文字列を分割します。
  • 新しく作成したテーブル(split_tab)をTable2(tab2)に結合します。
  • 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 
+0

クエリが最適化されていないため、CPUが100%に増加し、実行後に別のクエリに応答できません。 – user3728800

+0

@ user3728800テストしたところ、 –

+0

私はデータを抱きしめて、サンプル – user3728800

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; 
関連する問題