2013-10-09 10 views
8

私は2つの文字列 例では言葉の連続試合数を返すクエリたい:私は出現数の合計を取得するためにカウント二つの文字列で、順次、一致する単語はオラクル

Id column1    column2  result 
1 'foo bar live'  'foo bar'  2 
2 'foo live tele'  'foo tele'  1 
3 'bar foo live'  'foo bar live' 0 

select id, column1,column2, 
extractvalue(dbms_xmlgen.getxmltype('select cardinality (
    sys.dbms_debug_vc2coll(''' || replace(lower(column1), ' ', ''',''') || ''') multiset intersect 
    sys.dbms_debug_vc2coll('''||replace(lower(column2), ' ', ''',''')||''')) x from dual'), '//text()') cnt 
from table. 

類似の行については、逐次一致の数と出現数一緒に示されている。

+0

使用しているOracleのバージョンは? –

+0

oracle 11gを使用しています – user2342436

+0

この問題を解決するためにユーザー定義関数を使用することを検討しますか? –

答えて

3

個人的には、この状況では、プレーンSQLでPL/SQLコードを選択します。以下のような何か:

パッケージ仕様:

create or replace package PKG is 
    function NumOfSeqWords(
    p_str1 in varchar2, 
    p_str2 in varchar2 
) return number; 
end; 

パッケージ本体:

create or replace package body PKG is 
    function NumOfSeqWords(
    p_str1 in varchar2, 
    p_str2 in varchar2 
) return number 
    is 
    l_str1  varchar2(4000) := p_str1; 
    l_str2  varchar2(4000) := p_str2; 
    l_res  number default 0; 
    l_del_pos1 number; 
    l_del_pos2 number; 
    l_word1 varchar2(1000); 
    l_word2 varchar2(1000); 
    begin 
    loop 
     l_del_pos1 := instr(l_str1, ' '); 
     l_del_pos2 := instr(l_str2, ' '); 
     case l_del_pos1 
     when 0 
     then l_word1 := l_str1; 
      l_str1 := ''; 
     else l_word1 := substr(l_str1, 1, l_del_pos1 - 1); 
     end case; 
     case l_del_pos2 
     when 0 
     then l_word2 := l_str2; 
      l_str2 := ''; 
     else l_word2 := substr(l_str2, 1, l_del_pos2 - 1); 
     end case; 
     exit when (l_word1 <> l_word2) or 
       ((l_word1 is null) or (l_word2 is null)); 

     l_res := l_res + 1; 
     l_str1 := substr(l_str1, l_del_pos1 + 1); 
     l_str2 := substr(l_str2, l_del_pos2 + 1); 
    end loop; 
    return l_res; 
    end; 
end; 

テストケース:

with t1(Id1, col1, col2) as(
    select 1, 'foo bar live' ,'foo bar'  from dual union all 
    select 2, 'foo live tele' ,'foo tele' from dual union all 
    select 3, 'bar foo live' ,'foo bar live'from dual 
) 
    select id1 
     , col1 
     , col2 
     , pkg.NumOfSeqWords(col1, col2) as res 
    from t1 
    ; 

結果:

 ID1 COL1   COL2    RES 
---------- ------------- ------------ ---------- 
     1 foo bar live foo bar    2 
     2 foo live tele foo tele    1 
     3 bar foo live foo bar live   0 
3

なぜクエリのアプローチをあきらめますか? SQLFidlle

SELECT Table1.id, 
     Table1.column1, 
     Table1.column2, 
     max(nvl(t.l,0)) RESULT 
FROM (
    SELECT id, 
      column1, 
      column2, 
      LEVEL l, 
      decode(LEVEL, 
        1, 
       substr(column1, 1, instr(column1,' ', 1, LEVEL) -1), 
       substr(column1, 1, (instr(column1,' ', 1, LEVEL))) 
       ) sub1, 
      decode(LEVEL, 
        1, 
       substr(column2, 1, instr(column2,' ', 1, LEVEL) -1), 
       substr(column2, 1, (instr(column2,' ', 1, LEVEL))) 
       ) sub2 

    FROM (SELECT id, 
        column1 || ' ' column1, 
        column2 || ' ' column2 
      FROM Table1) 
    WHERE decode(LEVEL, 
         1, 
        substr(column1, 1, instr(column1,' ', 1, LEVEL) -1), 
        substr(column1, 1, (instr(column1,' ', 1, LEVEL))) 
       ) = 
      decode(LEVEL, 
         1, 
        substr(column2, 1, instr(column2,' ', 1, LEVEL) -1), 
        substr(column2, 1, (instr(column2,' ', 1, LEVEL))) 
       ) 
    START WITH column1 IS NOT NULL 
    CONNECT BY instr(column1,' ', 1, LEVEL) > 0 
) t 
RIGHT OUTER JOIN Table1 ON trim(t.column1) = Table1.column1 
         AND trim(t.column2) = Table1.column2 
         AND t.id = Table1.id 
GROUP BY Table1.id, 
      Table1.column1, 
      Table1.column2 
ORDER BY max(nvl(t.l,0)) DESC 
にここ

...私はそれは少し複雑だ知っていると私は、誰かがそれを改善するためにそれに取り組むことを願って、私は通話の午後を乗り切ることができた私の空き時間にこれに取り組んで

関連する問題