LoginSignup
22
15

More than 5 years have passed since last update.

PostgreSQL でカタカナ変換(ユーザ定義関数)

Last updated at Posted at 2014-11-03

概要

  • Version 8.4.13
  • PostgreSQL にはカタカナを変換する関数がないのでユーザ定義関数(ストアドプロシージャ)を作成する。
  • PHP の mb_convert_kana() と仕様を合わせました。

準備

PL/pgSQL(ユーザ定義関数)が使用可能か調べる。
データベースにログインして下のコマンドを実行。

select lanname from pg_language;

出力結果

 lanname  
----------
 internal
 c
 sql
(3 行)

"plpgsql" が見つからないので作成する。

create language plpgsql;

出力結果

CREATE LANGUAGE
# select lanname from pg_language;
 lanname  
----------
 internal
 c
 sql
 plpgsql
(4 行)

"plpgsql" が追加されました。

ユーザ定義関数

php の mb_convert_kana() のような関数を作成しました。
http://php.net/manual/ja/function.mb-convert-kana.php

mb_convert_kana.sql
create or replace function mb_convert_kana(text, varchar) returns text
as $$
  DECLARE
    str alias for $1;
    option alias for $2;
    ret text;
    option_str text;
    i   int;
    loop_count int;
    option_v boolean;
    get_char varchar;
    hira_dakuten_zen varchar = '゛';
    kata_dakuten_zen varchar = '゛';
    kata_dakuten_han varchar = '゙';
    hira_zen varchar = 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをんぁぃぅぇぉっゃゅょわいえー';
    kata_zen varchar = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォッャュョヮヰヱー';
    kata_han varchar = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォッャュョワイエー';
    daku_hira_zen varchar[] = array['が', 'ぎ', 'ぐ', 'げ', 'ご', 'ざ', 'じ', 'ず', 'ぜ', 'ぞ', 'だ', 'ぢ', 'づ', 'で', 'ど', 'ば', 'び', 'ぶ', 'べ', 'ぼ', 'ぱ', 'ぴ', 'ぷ', 'ぺ', 'ぽ', 'ぶ'];
    daku_kata_zen varchar[] = array['ガ', 'ギ', 'グ', 'ゲ', 'ゴ', 'ザ', 'ジ', 'ズ', 'ゼ', 'ゾ', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド', 'バ', 'ビ', 'ブ', 'ベ', 'ボ', 'パ', 'ピ', 'プ', 'ペ', 'ポ', 'ヴ'];
    daku_kata_han varchar[] = array['ガ', 'ギ', 'グ', 'ゲ', 'ゴ', 'ザ', 'ジ', 'ズ', 'ゼ', 'ゾ', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド', 'バ', 'ビ', 'ブ', 'ベ', 'ボ', 'パ', 'ピ', 'プ', 'ペ', 'ポ', 'ヴ'];
    num_zen varchar = '0123456789';
    num_han varchar = '0123456789';
    eng_zen varchar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    eng_han varchar = 'abcdefghijklmnopqrstuvwxyz';
  BEGIN
    ret = str;
    option_str = option;
    loop_count := 0;
    option_v = false;

    option_str = replace(option_str, 'a', 'rn');
    option_str = replace(option_str, 'A', 'RN');

    LOOP
      EXIT WHEN length(option_str) <= loop_count;
      get_char = substr(option_str, loop_count + 1, 1);
      if get_char = 'V' then
        option_v = true;
      end if;
      loop_count := loop_count + 1;
    END LOOP;

    loop_count := 0;
    LOOP
      EXIT WHEN length(option_str) <= loop_count;
      -- postgres の substr() の from は 1 から始まる
      get_char = substr(option_str, loop_count + 1, 1);

      if get_char = 'c' then
        -- 2バイトで変換
        -- 26 : count(hira_zen)
        for i in 1..26 loop
          ret = replace(ret, daku_kata_zen[i], daku_hira_zen[i]);
        end loop;
        -- 1バイトで変換
        ret = translate(ret, kata_zen, hira_zen);
      elsif get_char = 'C' then
        for i in 1..26 loop
          ret = replace(ret, daku_hira_zen[i], daku_kata_zen[i]);
        end loop;
        ret = translate(ret, hira_zen, kata_zen);
      elsif get_char = 'k' then
        for i in 1..26 loop
          ret = replace(ret, daku_kata_zen[i], daku_kata_han[i]);
        end loop;
        ret = translate(ret, kata_zen, kata_han);
      elsif get_char = 'K' then
        if option_v then
          for i in 1..26 loop
            ret = replace(ret, daku_kata_han[i], daku_kata_zen[i]);
          end loop;
          ret = translate(ret, kata_han, kata_zen);
        else
          ret = translate(ret, kata_han, kata_zen);
          ret = translate(ret, kata_dakuten_han, kata_dakuten_zen);
        end if;
      elsif get_char = 'h' then
        for i in 1..26 loop
          ret = replace(ret, daku_hira_zen[i], daku_kata_han[i]);
        end loop;
        ret = translate(ret, hira_zen, kata_han);
      elsif get_char = 'H' then
        if option_v then
          for i in 1..26 loop
            ret = replace(ret, daku_kata_han[i], daku_hira_zen[i]);
          end loop;
          ret = translate(ret, kata_han, hira_zen);
        else
          ret = translate(ret, kata_han, hira_zen);
          ret = translate(ret, kata_dakuten_han, hira_dakuten_zen);
        end if;
      elsif get_char = 'n' then
        ret = translate(ret, num_zen, num_han);
      elsif get_char = 'N' then
        ret = translate(ret, num_han, num_zen);
      elsif get_char = 'r' then
        ret = translate(ret, eng_zen, eng_han);
      elsif get_char = 'R' then
        ret = translate(ret, eng_han, eng_zen);
      elsif get_char = 's' then
        ret = replace(ret, ' ', ' ');
      elsif get_char = 'S' then
        ret = replace(ret, ' ', ' ');
      end if;
      loop_count := loop_count + 1;
    END LOOP;

    return ret;
  END;
$$ language 'plpgsql';

上記のSQLファイルをデータベースにインポートしてください。

psql DatabaseName < /.../mb_convert_kana.sql

データベースに登録されたかどうかは下のコマンドで確認できます。

select proname from pg_proc where proname = 'mb_convert_kana';

出力結果

     proname     
-----------------
 mb_convert_kana

データベースから削除するコマンドはこちらです。

drop function mb_convert_kana(text, varchar);

使用例

# select mb_convert_kana('A1', 'a');
 mb_convert_kana 
-----------------
 a1
# select mb_convert_kana('ガ', 'KV');
 mb_convert_kana 
-----------------
 ガ

最後に

  • ユーザ定義関数はデータベースに登録されるので関数が定義されていることが他の人から分かりづらくなります。プロジェクトで扱うときはデータベースの .sql を管理したり仕様書に記載しておくと良いと思います。
22
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
15