PL/SQLで文字列結合と文字列分割をやってみんとす

PL/SQLって文字列操作はあまり得意じゃないのね。って組んでみたはいいけど日の目を見ることはなかったので,これで成仏してくれ。
↓ここらへんを参考にした。


文字列結合の例
関数:SAMPLE.to_str()が可変長引数なのがポイント。組み込み関数だと可変長引数もアリなのに,ユーザ関数じゃ,トリック使わないとできないってどうゆうこと。
#→UTL_LMS.FORMAT_MESSAGEファンクション

DECLARE
  result VARCHAR2(200);
BEGIN
  -- 可変引数なのがポイント
  result := SAMPLE.to_str(SAMPLE.vargs('a', 'b'));
  DBMS_OUTPUT.PUT_LINE('result = ' || result);

  result := SAMPLE.to_str(SAMPLE.vargs('a', 'b', 'c'));
  DBMS_OUTPUT.PUT_LINE('result = ' || result);
END;


文字列分割の例
splitって予約語っぽいんだけど,文字列分割じゃないみたい。しょうがないので自作するハメになった(ググると色んな実装が出てくる)。

BEGIN
  -- デフォは カンマ(,) 区切
  FOR token IN (SELECT * from table(SAMPLE.split_str('abc,def,ghi'))) LOOP
    DBMS_OUTPUT.PUT_LINE(token.COLUMN_VALUE);
  END LOOP;

  -- デリミタを指定できる
  FOR token IN (SELECT * from table(SAMPLE.split_str('あいうえお かきくけこ', ' '))) LOOP
    DBMS_OUTPUT.PUT_LINE(token.COLUMN_VALUE);
  END LOOP;
END;


本体のコードはこんなの。結構ツメが甘いので,ご利用の際はお気をつけて〜。

CREATE OR REPLACE PACKAGE SAMPLE AS
  TYPE split_type IS TABLE OF VARCHAR2(200);
  TYPE vargs IS TABLE OF VARCHAR2(32767);

  FUNCTION to_str(args vargs) RETURN VARCHAR2;

  FUNCTION split_str(
    target_list VARCHAR2,
    delimter VARCHAR2 := ','
  ) RETURN split_type PIPELINED;
END SAMPLE;


CREATE OR REPLACE PACKAGE BODY SAMPLE AS
  FUNCTION to_str(args vargs) RETURN VARCHAR2 IS
    result_str VARCHAR2(32767) := '';
    work_str VARCHAR2(32767) := '';
    idx pls_integer;
  BEGIN
    FOR idx IN 1..(args.count) LOOP
      work_str := args(idx);
      IF work_str IS NOT NULL THEN
        IF result_str IS NULL THEN
          result_str := work_str;
        ELSE
          result_str := result_str || ',' || work_str;
        END IF;
      END IF;
    END LOOP;
    RETURN result_str;
  END to_str;


  FUNCTION split_str(
    target_list varchar2,
    delimter varchar2 := ','
  ) RETURN split_type PIPELINED
  IS
    l_idx    pls_integer;
    l_list   VARCHAR2(32767) := target_list;
    l_value  VARCHAR2(200);
  BEGIN
    LOOP
      l_idx := INSTR(l_list, delimter);
      IF l_idx > 0 THEN
        PIPE ROW(SUBSTR(l_list, 1, l_idx - 1));
        l_list := SUBSTR(l_list, l_idx + LENGTH(delimter));
      ELSE
        PIPE ROW(l_list);
        EXIT;
      END IF;
    END LOOP;
  END split_str;
END SAMPLE;