はじめに
PostgreSQL
のLENGTH
関数、OCTET_LENGTH
関数について使ってみた。
また、おまけで半角カタカナのバイト数を変えてみるなどもやってみた。
環境
Windows 11 Professional
PostgreSQL 17
Docker Desktop 4.37.0 (178034)
LENGTH関数
- 9.4. 文字列関数と演算子 | PostgreSQL 16.4文書
https://www.postgresql.jp/document/16/html/functions-string.html
LENGTH
関数は 文字列内の文字数を返す関数となっている。length ( text ) → integer
動作を見る
SELECT
input AS 入力データ,
LENGTH (input) AS 文字数
FROM (VALUES
('abcdefア'), -- 半角カタカナ含む
('abcdefア'), -- 全角カタカナ
('abcdef'), -- 半角英数字のみ
('アア'), -- 全角と半角カタカナの混合
('12345'), -- 数字のみ
('日本語'), -- 漢字
('😊') -- 絵文字
) AS test_data(input);
結果
入力データ | 文字数 |
---|---|
abcdefア | 7 |
abcdefア | 7 |
abcdef | 6 |
アア | 2 |
12345 | 5 |
日本語 | 3 |
😊 | 1 |
OCTET_LENGTH関数
- 9.4. 文字列関数と演算子 | PostgreSQL 16.4文書
https://www.postgresql.jp/document/16/html/functions-string.html
OCTET_LENGTH
関数は 文字列のバイト数を返す関数となっている。octet_length ( text ) → integer
※サーバーエンコーディングにより返すバイト数は異なるので注意。
今回は、エンコーディングはUTF8
で確認をしている。 (\l
で確認)
名前 | オーナー | エンコーディング | ロケールプロバイダー | コレーション | Ctype | ロケール | ICUルール | アクセス権限 |
---|---|---|---|---|---|---|---|---|
postgres | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | |||
template0 | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | =c/postgres + | ||
postgres=CTc/postgres | ||||||||
template1 | postgres | UTF8 | libc | en_US.utf8 | en_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 |
abcdef | 6 |
アア | 6 |
12345 | 5 |
日本語 | 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;
動作説明
string_to_array
とunnest
の使用:文字列を1文字ずつ分割し、各文字を処理する。
string_to_array
は文字列を配列に変換し、unnest
を使ってそれをループ処理する。
半角カタカナの判定:
正規表現
[\\uFF61-\\uFF9F]
を使用して、現在の文字が半角カタカナかどうかをチェックする。半角カタカナの場合は 1バイト としてカウントする。
通常のバイト長の計算:
- 半角カタカナ以外の文字については、通常の
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ア | 7 | 9 | 7 |
abcdefア | 7 | 9 | 9 |
abcdef | 6 | 6 | 6 |
アア | 2 | 6 | 4 |
12345 | 5 | 5 | 5 |
スポーン | 4 | 12 | 12 |
スポーン | 5 | 15 | 5 |
補足
関数内部で1文字ずつ処理するため、大量のデータに対してはパフォーマンスの影響を考慮する必要がある。
必要に応じて、半角カタカナ以外にも特定の文字種を追加したり変更することが可能。
参考
9.4. 文字列関数と演算子 | PostgreSQL 16.4文書
https://www.postgresql.jp/document/16/html/functions-string.html[PostgreSQL] あんたは一体、何 length だい?
https://zenn.dev/collabostyle/articles/6ef28b398a466eUTF8 文字コード表 3byte (ef)
https://orange-factory.com/sample/utf8/code3/ef.html#HalfwidthandFullwidthFormsUnicode一覧_F000-FFFF | wikipedia
https://ja.wikipedia.org/wiki/Unicode%E4%B8%80%E8%A6%A7_F000-FFFF
おわりに
LENGTH
, OCTET_LENGTH
についてちょっと調べた。
文字コードについてもまたの機会に調べよう…。
文字コード自体を体系的に勉強しておきたい気持ちはある。