PostgreSQLでLENGTH, OCTET_LENGTHを使う

はじめに

PostgreSQLLENGTH関数、OCTET_LENGTH関数について使ってみた。
また、おまけで半角カタカナのバイト数を変えてみるなどもやってみた。

環境

Windows 11 Professional
PostgreSQL 17
Docker Desktop 4.37.0 (178034)

LENGTH関数

LENGTH関数は 文字列内の文字数を返す関数となっている。
length ( text ) → integer

動作を見る

SELECT 
    input AS 入力データ,
    LENGTH (input) AS 文字数
FROM (VALUES
    ('abcdefア'),    -- 半角カタカナ含む
    ('abcdefア'),    -- 全角カタカナ
    ('abcdef'),      -- 半角英数字のみ
    ('アア'),         -- 全角と半角カタカナの混合
    ('12345'),        -- 数字のみ
    ('日本語'),       -- 漢字
    ('😊')          -- 絵文字
) AS test_data(input);

結果

入力データ文字数
abcdefア7
abcdefア7
abcdef6
アア2
123455
日本語3
😊1

OCTET_LENGTH関数

OCTET_LENGTH関数は 文字列のバイト数を返す関数となっている。
octet_length ( text ) → integer

※サーバーエンコーディングにより返すバイト数は異なるので注意。

今回は、エンコーディングはUTF8で確認をしている。 (\lで確認)

名前オーナーエンコーディングロケールプロバイダーコレーションCtypeロケールICUルールアクセス権限
postgrespostgresUTF8libcen_US.utf8en_US.utf8
template0postgresUTF8libcen_US.utf8en_US.utf8=c/postgres +
postgres=CTc/postgres
template1postgresUTF8libcen_US.utf8en_US.utf8=c/postgres +
postgres=CTc/postgres

動作を見る

SELECT 
    input AS 入力データ,
    OCTET_LENGTH (input) AS バイト数
FROM (VALUES
    ('abcdefア'),    -- 半角カタカナ含む
    ('abcdefア'),    -- 全角カタカナ
    ('abcdef'),      -- 半角英数字のみ
    ('アア'),         -- 全角と半角カタカナの混合
    ('12345'),        -- 数字のみ
    ('日本語'),       -- 漢字
    ('😊')          -- 絵文字
) AS test_data(input);

結果

入力データバイト数
abcdefア9
abcdefア9
abcdef6
アア6
123455
日本語9
😊4

おまけ: 半角カタカナのみ1バイトで計算するカスタム関数を作成する

PostgreSQL の OCTET_LENGTH 関数をそのまま使う場合、半角カタカナは実際には 3 バイトとして計算されるため、半角カタカナを特別に 1 バイトとして扱うカスタム関数を作成する。

関数

CREATE OR REPLACE FUNCTION octet_length_with_hankaku_as_single_byte(input character varying)
RETURNS INTEGER AS $$
DECLARE
    total_length INTEGER := 0;  -- カスタムバイト長の合計
    current_char character varying;          -- 文字を1つずつ処理するための変数
BEGIN
    FOR current_char IN SELECT unnest(regexp_split_to_array(input, '')) LOOP
        -- 半角カタカナの場合は1バイトとして加算
        IF current_char ~ '[\uFF61-\uFF9F]' THEN
            total_length := total_length + 1;
        -- その他の文字は通常のOCTET_LENGTHで加算
        ELSE
            total_length := total_length + OCTET_LENGTH(current_char);
        END IF;
    END LOOP;
    RETURN total_length;
END;
$$ LANGUAGE plpgsql;

動作説明

  1. string_to_arrayunnest の使用:

    • 文字列を1文字ずつ分割し、各文字を処理する。

    • string_to_array は文字列を配列に変換し、unnest を使ってそれをループ処理する。

  2. 半角カタカナの判定:

    • 正規表現 [\\uFF61-\\uFF9F] を使用して、現在の文字が半角カタカナかどうかをチェックする。

    • 半角カタカナの場合は 1バイト としてカウントする。

  3. 通常のバイト長の計算:

    • 半角カタカナ以外の文字については、通常の OCTET_LENGTH を使用する。

使用例

以下のように動作を確認をする

サンプルデータ

SELECT 
    input AS 入力データ,
    LENGTH (input) AS 文字数,
    OCTET_LENGTH(input) AS 通常バイト長,
    octet_length_with_hankaku_as_single_byte(input) AS カスタムバイト長
FROM (VALUES
    ('abcdefア'),     -- 半角カタカナ含む
    ('abcdefア'),    -- 全角カタカナ
    ('abcdef'),      -- 半角英数字のみ
    ('アア'),         -- 全角と半角カタカナの混合
    ('12345'),        -- 数字のみ
    ('スポーン'),      -- 全角カタカナ 半濁音あり
    ('スポーン')        -- 半角カタカナ 半濁音あり
) AS test_data(input);

実行結果

入力データ文字数通常バイト長カスタムバイト長
abcdefア797
abcdefア799
abcdef666
アア264
12345555
スポーン41212
スポーン5155

補足

  • 関数内部で1文字ずつ処理するため、大量のデータに対してはパフォーマンスの影響を考慮する必要がある。

  • 必要に応じて、半角カタカナ以外にも特定の文字種を追加したり変更することが可能。

参考

おわりに

LENGTH, OCTET_LENGTHについてちょっと調べた。
文字コードについてもまたの機会に調べよう…。 文字コード自体を体系的に勉強しておきたい気持ちはある。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。