【Oracle】LENGTH / LENGTHB で文字数・バイト数を取得する方法|全LENGTH関数・VARCHAR2 BYTE/CHAR・VSIZE・NLS設定まで解説

【Oracle】LENGTH / LENGTHB で文字数・バイト数を取得する方法|全LENGTH関数・VARCHAR2 BYTE/CHAR・VSIZE・NLS設定まで解説 Oracle

Oracle で文字列の長さを取得するには LENGTH(文字数)と LENGTHB(バイト数)を使います。しかし「日本語で LENGTHB の結果が 3 倍になる」「空文字列の LENGTH が NULL になる」「VARCHAR2(100 BYTE) に日本語が 33 文字しか入らない」といった疑問に悩まされることは多いものです。

これらはすべて文字セット(NLS_CHARACTERSET)VARCHAR2 の BYTE / CHAR セマンティクスに起因します。本記事では、LENGTH 系関数の全種類を比較しながら、文字セットによるバイト数の違いVSIZE 関数NLS_LENGTH_SEMANTICS の設定、そしてバイト数超過チェックなどの実務パターンまで体系的に解説します。

この記事でわかること
・LENGTH(文字数)と LENGTHB(バイト数)の基本
・LENGTHC / LENGTH2 / LENGTH4 の用途
・文字セット(AL32UTF8 / JA16SJIS 等)によるバイト数の違い
・VARCHAR2(N BYTE) と VARCHAR2(N CHAR) の関係
・VSIZE 関数で内部格納バイト数を取得する方法
・LENGTH(”) が NULL を返す Oracle の仕様
・CLOB の文字数・バイト数を取得する方法
・バイト数超過チェック・マルチバイト文字検出の実務パターン
スポンサーリンク

LENGTH と LENGTHB の基本

SQL(LENGTH / LENGTHB 基本)
-- LENGTH: 文字数を返す
SELECT LENGTH('Oracle') AS char_count FROM dual;   -- 6
SELECT LENGTH('日本語')  AS char_count FROM dual;   -- 3

-- LENGTHB: バイト数を返す
SELECT LENGTHB('Oracle') AS byte_count FROM dual;  -- 6(半角英数は 1 バイト/文字)
SELECT LENGTHB('日本語') AS byte_count FROM dual;  -- 9(AL32UTF8 の場合: 3 バイト/文字)
-- JA16SJIS の場合は 6(2 バイト/文字)
入力値 LENGTH(文字数) LENGTHB(AL32UTF8) LENGTHB(JA16SJIS)
‘ABC’ 3 3 3
‘日本語’ 3 9(3×3バイト) 6(3×2バイト)
‘Aあ1’ 3 5(1+3+1) 4(1+2+1)
‘①②③’ 3 9(3×3バイト) 6(3×2バイト)
‘ ‘(半角スペース) 1 1 1
NULL NULL NULL NULL
LENGTHB の結果は文字セットで変わる
同じ日本語文字列でも、データベースの文字セットが AL32UTF8 なら 3 バイト/文字、JA16SJIS なら 2 バイト/文字になります。LENGTHB の結果を見て「バイト数がおかしい」と思ったら、まず NLS_CHARACTERSET を確認してください。
SQL(データベースの文字セットを確認)
-- データベースの文字セットを確認
SELECT parameter, value FROM NLS_DATABASE_PARAMETERS
WHERE parameter = 'NLS_CHARACTERSET';
-- 結果例: AL32UTF8

LENGTH 系関数の全種類

関数 返す値 用途
LENGTH(str) 文字数 最も一般的。文字セットに関係なく文字数を返す
LENGTHB(str) バイト数 VARCHAR2(N BYTE) の上限チェックに必須
LENGTHC(str) Unicode 合成文字を考慮した文字数 合成文字(é = e + ́)を 1 文字として数える
LENGTH2(str) UCS-2 コードユニット数 Unicode サロゲートペアの検出に使用
LENGTH4(str) UCS-4 コードポイント数 Unicode コードポイント単位の正確な文字数
SQL(LENGTH / LENGTHC / LENGTH2 / LENGTH4 の比較)
-- 通常の日本語: すべて同じ結果
SELECT
    LENGTH('日本語')  AS len,     -- 3
    LENGTHB('日本語') AS lenb,    -- 9(AL32UTF8)
    LENGTHC('日本語') AS lenc,    -- 3
    LENGTH2('日本語') AS len2,    -- 3
    LENGTH4('日本語') AS len4     -- 3
FROM dual;

-- 絵文字(サロゲートペア文字): LENGTH2 だけ異なる場合がある
-- 例: U+1F600(?)は UTF-16 で 2 コードユニット
実務では LENGTH と LENGTHB だけで十分
LENGTHC / LENGTH2 / LENGTH4 は Unicode の合成文字やサロゲートペアを扱う特殊なケースでのみ必要です。通常の業務アプリケーションでは LENGTH(文字数)と LENGTHB(バイト数)だけ覚えれば問題ありません。

VARCHAR2(N BYTE) と VARCHAR2(N CHAR) の関係

VARCHAR2 列の定義には BYTE セマンティクスCHAR セマンティクスの 2 種類があり、LENGTH / LENGTHB との関係を理解することが重要です。

定義 格納上限 AL32UTF8 での日本語最大文字数 確認関数
VARCHAR2(100 BYTE) 100 バイト 33 文字(100÷3=33.3) LENGTHB で上限チェック
VARCHAR2(100 CHAR) 100 文字 100 文字(バイト数は最大 300) LENGTH で上限チェック
SQL(BYTE / CHAR セマンティクスの確認)
-- テーブルの列が BYTE か CHAR かを確認
SELECT column_name, data_type, data_length, char_used,
       CASE char_used
           WHEN 'B' THEN 'BYTE セマンティクス'
           WHEN 'C' THEN 'CHAR セマンティクス'
       END AS semantics
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
ORDER BY column_id;

-- CHAR_USED 列: B=BYTE, C=CHAR
SQL(NLS_LENGTH_SEMANTICS の確認と設定)
-- セッションのデフォルト LENGTH_SEMANTICS を確認
SELECT parameter, value FROM NLS_SESSION_PARAMETERS
WHERE parameter = 'NLS_LENGTH_SEMANTICS';
-- 結果: BYTE(デフォルト)または CHAR

-- セッション単位で変更
ALTER SESSION SET NLS_LENGTH_SEMANTICS = CHAR;
-- 以降の CREATE TABLE で VARCHAR2(100) は VARCHAR2(100 CHAR) として作成される
VARCHAR2(100) と書いたときの意味
VARCHAR2(100)NLS_LENGTH_SEMANTICS の設定に依存します。デフォルト(BYTE)なら VARCHAR2(100 BYTE)、CHAR に設定されていれば VARCHAR2(100 CHAR) として解釈されます。混乱を防ぐため、BYTE / CHAR を明示的に指定することを推奨します。

VSIZE 関数:内部格納バイト数を取得する

VSIZE は Oracle 独自の関数で、値の内部格納サイズ(バイト数)を返します。LENGTHB と似ていますが、NUMBER 型や DATE 型にも使える点が異なります。

SQL(VSIZE の使用例)
-- 文字列: LENGTHB と同じ結果
SELECT VSIZE('ABC')   AS vsize_abc FROM dual;    -- 3
SELECT VSIZE('日本語') AS vsize_jp FROM dual;     -- 9(AL32UTF8)

-- NUMBER 型: 内部格納サイズ
SELECT VSIZE(0)       AS vsize_0 FROM dual;       -- 1
SELECT VSIZE(123)     AS vsize_123 FROM dual;     -- 3
SELECT VSIZE(123.456) AS vsize_dec FROM dual;     -- 5

-- DATE 型: 固定 7 バイト
SELECT VSIZE(SYSDATE) AS vsize_date FROM dual;    -- 7

-- NULL
SELECT VSIZE(NULL)    AS vsize_null FROM dual;    -- NULL
関数 対象型 返す値 主な用途
LENGTHB 文字列のみ 文字列のバイト数 VARCHAR2 列のバイト数チェック
VSIZE 全データ型 内部格納バイト数 テーブルの行サイズ推定・ストレージ分析

LENGTH と NULL・空文字列の扱い

SQL(NULL と空文字列の LENGTH)
-- Oracle では空文字列は NULL として扱われる
SELECT LENGTH('')    AS len_empty FROM dual;  -- NULL(0 ではない!)
SELECT LENGTH(NULL)  AS len_null FROM dual;   -- NULL
SELECT LENGTHB('')   AS lenb_empty FROM dual;  -- NULL
SELECT LENGTHB(NULL) AS lenb_null FROM dual;   -- NULL

-- 半角スペース 1 文字は空文字列ではない
SELECT LENGTH(' ')   AS len_space FROM dual;   -- 1
Oracle では空文字列 = NULL
LENGTH('')0 ではなく NULL を返します。これは Oracle が空文字列を NULL と同一視する独自仕様です。「文字数が 0」かどうかを判定するには LENGTH(col) IS NULL を使うか、NVL(LENGTH(col), 0) = 0 と書きます。MySQL や PostgreSQL では LENGTH('') = 0 なので、他 RDBMS からの移行時は注意してください。
SQL(空文字列・NULL を安全にチェック)
-- 空文字列 / NULL を判定する安全なパターン
SELECT employee_id, name,
       NVL(LENGTH(name), 0) AS name_length,
       CASE WHEN name IS NULL THEN '空'
            ELSE TO_CHAR(LENGTH(name)) || '文字'
       END AS status
FROM employees;

CLOB の文字数・バイト数を取得する

SQL(CLOB の長さ取得)
-- CLOB に対して LENGTH は使える(文字数を返す)
SELECT LENGTH(clob_column) AS char_count FROM documents;

-- DBMS_LOB.GETLENGTH: CLOB の文字数(NUMBER 型で返す)
SELECT DBMS_LOB.GETLENGTH(clob_column) AS char_count FROM documents;

-- LENGTHB は CLOB に直接使えない(暗黙変換で 32767 バイトまで)
-- CLOB のバイト数を取得するには DBMS_LOB.GETLENGTH + LENGTHB を組み合わせるか、
-- CLOB を BLOB に変換して DBMS_LOB.GETLENGTH で取得

-- CLOB のバイト数(概算: 文字数 × 最大バイト/文字)
SELECT LENGTH(clob_column) * 3 AS max_bytes FROM documents;  -- AL32UTF8 の場合

実務パターン集

パターン①:VARCHAR2(BYTE) 列のバイト数超過チェック

SQL(INSERT 前のバイト数チェック)
-- name 列が VARCHAR2(100 BYTE) の場合、バイト数超過する行を事前検出
SELECT id, name,
       LENGTH(name)  AS char_count,
       LENGTHB(name) AS byte_count
FROM staging_data
WHERE LENGTHB(name) > 100;
-- この行を INSERT すると ORA-12899 が発生する

パターン②:マルチバイト文字を含む行の検出

SQL(マルチバイト文字の検出)
-- 文字数とバイト数が異なる = マルチバイト文字を含む
SELECT id, name,
       LENGTH(name)  AS chars,
       LENGTHB(name) AS bytes,
       LENGTHB(name) - LENGTH(name) AS multi_byte_extra
FROM products
WHERE LENGTH(name) <> LENGTHB(name);

-- 全角文字の割合を計算
SELECT id, name,
       ROUND((LENGTHB(name) - LENGTH(name)) * 100.0
             / NULLIF(LENGTHB(name), 0), 1) AS multibyte_pct
FROM products
WHERE LENGTH(name) <> LENGTHB(name);

パターン③:列定義の上限に近いデータの検出

SQL(列の上限に近いデータを検出)
-- 各 VARCHAR2 列で最大バイト数のデータを確認
SELECT 'NAME' AS col, MAX(LENGTHB(name)) AS max_bytes FROM employees
UNION ALL
SELECT 'ADDRESS', MAX(LENGTHB(address)) FROM employees
UNION ALL
SELECT 'EMAIL', MAX(LENGTHB(email)) FROM employees;

-- 列定義の 80% 以上を使用しているデータを検出
SELECT employee_id, name, LENGTHB(name) AS bytes,
       100 AS col_limit,
       ROUND(LENGTHB(name) / 100 * 100, 1) AS usage_pct
FROM employees
WHERE LENGTHB(name) > 100 * 0.8;  -- name が VARCHAR2(100 BYTE) の場合

パターン④:文字数で GROUP BY(文字数分布の分析)

SQL(文字数の分布分析)
-- 名前の文字数の分布を確認
SELECT LENGTH(name) AS char_count, COUNT(*) AS cnt
FROM employees
WHERE name IS NOT NULL
GROUP BY LENGTH(name)
ORDER BY char_count;

よくある質問

QLENGTH と LENGTHB の違いは何ですか?
ALENGTH文字数を返します(日本語 1 文字 = 1)。LENGTHBバイト数を返します(日本語 1 文字 = AL32UTF8 で 3 バイト、JA16SJIS で 2 バイト)。半角英数字はどちらも 1 を返すため、英数字のみのデータでは結果は同じです。
QLENGTH(”) が 0 ではなく NULL を返します
Aこれは Oracle の仕様です。Oracle では空文字列は NULL と同一として扱われます。LENGTH(NULL) は NULL を返すため、LENGTH('') も NULL になります。「文字数 0」を判定するには NVL(LENGTH(col), 0) = 0 と書いてください。
QVARCHAR2(100) に日本語が 33 文字しか入りません
AVARCHAR2(100) はデフォルトで 100 バイトを意味します。AL32UTF8 では日本語 1 文字 = 3 バイトなので、100 ÷ 3 = 33 文字が上限です。100 文字入れたい場合は VARCHAR2(100 CHAR) と定義するか、VARCHAR2(300 BYTE) と十分なバイト数を確保してください。
QLENGTHB の結果がサーバーによって異なります
ALENGTHB の結果はデータベースの NLS_CHARACTERSET に依存します。AL32UTF8 なら日本語 1 文字 = 3 バイト、JA16SJIS なら 2 バイトです。SELECT value FROM NLS_DATABASE_PARAMETERS WHERE parameter='NLS_CHARACTERSET' で確認してください。
QCLOB に LENGTHB は使えますか?
ACLOB に LENGTHB を使うと、暗黙的に VARCHAR2 に変換されるため32767 バイトを超えるデータではエラーになります。CLOB の文字数は LENGTH(clob_col) または DBMS_LOB.GETLENGTH(clob_col) で取得してください。
QVSIZE と LENGTHB の違いは何ですか?
A文字列に対しては同じ結果を返しますが、VSIZENUMBER 型や DATE 型にも使える点が異なります。VSIZE(SYSDATE) は 7(DATE 型の内部格納サイズ)を返します。テーブルの行サイズを推定したい場合に便利です。

まとめ

Oracle での文字数・バイト数取得の要点をまとめます。

やりたいこと 使う関数
文字数を取得 LENGTH(str)
バイト数を取得 LENGTHB(str)
NULL / 空文字列を安全にチェック NVL(LENGTH(str), 0)
内部格納バイト数(全型対応) VSIZE(value)
CLOB の文字数 DBMS_LOB.GETLENGTH(clob_col)
VARCHAR2 列が BYTE/CHAR か確認 USER_TAB_COLUMNS.CHAR_USED(B=BYTE, C=CHAR)
データベースの文字セット確認 NLS_DATABASE_PARAMETERS WHERE parameter=’NLS_CHARACTERSET’
バイト数超過する行を検出 WHERE LENGTHB(col) > 列のバイト上限
マルチバイト文字を含む行を検出 WHERE LENGTH(col) <> LENGTHB(col)

SQL 全般の LENGTH 関数(RDBMS 別の違い)については「LENGTH関数で文字列の長さを取得する方法」も併せて参照してください。