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 の基本
-- 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 |
同じ日本語文字列でも、データベースの文字セットが
AL32UTF8 なら 3 バイト/文字、JA16SJIS なら 2 バイト/文字になります。LENGTHB の結果を見て「バイト数がおかしい」と思ったら、まず NLS_CHARACTERSET を確認してください。-- データベースの文字セットを確認 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 コードポイント単位の正確な文字数 |
-- 通常の日本語: すべて同じ結果
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 コードユニット
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 で上限チェック |
-- テーブルの列が 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
-- セッションのデフォルト 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) は NLS_LENGTH_SEMANTICS の設定に依存します。デフォルト(BYTE)なら VARCHAR2(100 BYTE)、CHAR に設定されていれば VARCHAR2(100 CHAR) として解釈されます。混乱を防ぐため、BYTE / CHAR を明示的に指定することを推奨します。VSIZE 関数:内部格納バイト数を取得する
VSIZE は Oracle 独自の関数で、値の内部格納サイズ(バイト数)を返します。LENGTHB と似ていますが、NUMBER 型や DATE 型にも使える点が異なります。
-- 文字列: 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・空文字列の扱い
-- 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
LENGTH('') は 0 ではなく NULL を返します。これは Oracle が空文字列を NULL と同一視する独自仕様です。「文字数が 0」かどうかを判定するには LENGTH(col) IS NULL を使うか、NVL(LENGTH(col), 0) = 0 と書きます。MySQL や PostgreSQL では LENGTH('') = 0 なので、他 RDBMS からの移行時は注意してください。-- 空文字列 / 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 の文字数・バイト数を取得する
-- 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) 列のバイト数超過チェック
-- 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 が発生する
パターン②:マルチバイト文字を含む行の検出
-- 文字数とバイト数が異なる = マルチバイト文字を含む
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);
パターン③:列定義の上限に近いデータの検出
-- 各 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(文字数分布の分析)
-- 名前の文字数の分布を確認 SELECT LENGTH(name) AS char_count, COUNT(*) AS cnt FROM employees WHERE name IS NOT NULL GROUP BY LENGTH(name) ORDER BY char_count;
よくある質問
LENGTH は文字数を返します(日本語 1 文字 = 1)。LENGTHB はバイト数を返します(日本語 1 文字 = AL32UTF8 で 3 バイト、JA16SJIS で 2 バイト)。半角英数字はどちらも 1 を返すため、英数字のみのデータでは結果は同じです。LENGTH(NULL) は NULL を返すため、LENGTH('') も NULL になります。「文字数 0」を判定するには NVL(LENGTH(col), 0) = 0 と書いてください。VARCHAR2(100) はデフォルトで 100 バイトを意味します。AL32UTF8 では日本語 1 文字 = 3 バイトなので、100 ÷ 3 = 33 文字が上限です。100 文字入れたい場合は VARCHAR2(100 CHAR) と定義するか、VARCHAR2(300 BYTE) と十分なバイト数を確保してください。LENGTHB の結果はデータベースの NLS_CHARACTERSET に依存します。AL32UTF8 なら日本語 1 文字 = 3 バイト、JA16SJIS なら 2 バイトです。SELECT value FROM NLS_DATABASE_PARAMETERS WHERE parameter='NLS_CHARACTERSET' で確認してください。LENGTHB を使うと、暗黙的に VARCHAR2 に変換されるため32767 バイトを超えるデータではエラーになります。CLOB の文字数は LENGTH(clob_col) または DBMS_LOB.GETLENGTH(clob_col) で取得してください。VSIZE は NUMBER 型や 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関数で文字列の長さを取得する方法」も併せて参照してください。

