【Oracle】ORA-00947の原因と解決方法|値の個数が足りません

【Oracle】ORA-00947の原因と解決方法|値の個数が足りません Oracle

ORA-00947: not enough values は、Oracleで INSERT 文を実行した時に、登録先の列数に対して VALUES 句や SELECT 句の値の数が足りない場合に発生するエラーです。

よくある原因は、列リストを省略したINSERT、列を追加した後に古いINSERT文を使っている、INSERT INTO ... SELECT のSELECT列数が足りない、INSERT ALL の値数が合っていない、DEFAULTやNULLで埋めるべき列を省いている、といったパターンです。

先に結論
ORA-00947は「入れる列数」と「渡す値数」が合っていないエラーです。まず INSERT INTO table_name (列1, 列2, ...) の列リストを明示し、VALUES または SELECT の値数と1対1で対応しているか確認します。
スポンサーリンク

ORA-00947とは

Oracle公式のエラー説明では、ORA-00947はSQL文で必要な2つの値セットの片方に、十分な値がない時に発生します。代表例は、INSERT文の VALUES 句や SELECT 句に、INSERT先で必要な値が足りないケースです。

INSERT/UPDATE/DELETEの基本は INSERT・UPDATE・DELETE完全ガイド、テーブル定義の確認は CREATE TABLE完全ガイド も参考になります。

最小の再現例

次のテーブルは3列あります。列リストを省略して2つだけ値を渡すと、Oracleは全列に値が必要だと判断し、ORA-00947になります。

create-sample-table.sql
CREATE TABLE app_user (
  user_id   NUMBER,
  user_name VARCHAR2(100),
  status    VARCHAR2(20)
);
bad-insert-not-enough-values.sql
INSERT INTO app_user
VALUES (1, 'tanaka');

-- ORA-00947: not enough values

列リストを明示して、値の数を合わせます。未指定列をNULLにしたい場合は列リストから外し、値を入れたい場合はVALUESに追加します。

fixed-insert-column-list.sql
INSERT INTO app_user (user_id, user_name)
VALUES (1, 'tanaka');

-- status は省略されるため NULL になる
fixed-insert-all-values.sql
INSERT INTO app_user (user_id, user_name, status)
VALUES (1, 'tanaka', 'ACTIVE');

発生しやすいパターン

列リストを省略している

テーブルの全列に対して値が必要になります。列追加後に古いINSERT文を実行すると起きやすいです。

INSERT列数よりVALUESが少ない

INSERT INTO t (a, b, c) VALUES (1, 2) のように、列数と値数が合っていないケースです。

INSERT INTO SELECTのSELECT列が少ない

INSERT先の列リストが4列なのに、SELECT句が3列しか返していないケースです。

INSERT ALLでINTOごとの値数が足りない

複数表INSERTで、一部のINTO句だけ列数と値数がずれているケースです。

テーブル定義が変わった

列追加・削除・INVISIBLE列・DEFAULT変更などで、既存SQLとテーブル定義がずれているケースです。

テーブル列数を確認するSQL

まず、INSERT先テーブルにどの列があるか確認します。列リストを省略している場合は、ここに表示される列の数と順番が重要になります。

check-table-columns.sql
SELECT column_id,
       column_name,
       data_type,
       nullable,
       data_default,
       hidden_column,
       virtual_column,
       identity_column
FROM user_tab_cols
WHERE table_name = UPPER('&TABLE_NAME')
ORDER BY column_id;
INSERTでは列リストを明示する
列リスト省略のINSERTは、テーブル定義変更に弱くなります。実務では INSERT INTO table_name (col1, col2, ...) の形を基本にすると、ORA-00947だけでなく意図しない列ずれも防げます。

INSERT対象列を数えるSQL

列リストを省略しているSQLを調べる時は、通常のINSERTで対象になりうる列を数えると切り分けが速くなります。仮想列や一部の生成列は明示的に値を入れられないため、単純な列数だけで判断しないようにします。

count-insert-target-columns.sql
SELECT COUNT(*) AS insert_target_columns
FROM user_tab_cols
WHERE table_name = UPPER('&TABLE_NAME')
  AND hidden_column = 'NO'
  AND virtual_column = 'NO';
list-insert-target-columns.sql
SELECT column_id,
       column_name,
       nullable,
       data_default,
       identity_column
FROM user_tab_cols
WHERE table_name = UPPER('&TABLE_NAME')
  AND hidden_column = 'NO'
  AND virtual_column = 'NO'
ORDER BY column_id;

INSERT INTO SELECTで発生する例

INSERT INTO ... SELECT では、INSERT先の列リストとSELECT句の列数を合わせます。列名ではなく、列の数と順番で対応する点に注意します。

bad-insert-select.sql
INSERT INTO app_user (user_id, user_name, status)
SELECT employee_id,
       employee_name
FROM employees;

-- INSERT先は3列、SELECTは2列なので ORA-00947
fixed-insert-select.sql
INSERT INTO app_user (user_id, user_name, status)
SELECT employee_id,
       employee_name,
       'ACTIVE' AS status
FROM employees;

DEFAULTやNULLで埋める

値が未定の場合は、列リストから外す、NULL を明示する、DEFAULT を使う、のいずれかを選びます。ただし、NOT NULL列やCHECK制約がある列では、NULLやDEFAULTが許可されるか確認が必要です。

insert-null-default.sql
INSERT INTO app_user (user_id, user_name, status)
VALUES (1, 'tanaka', DEFAULT);

INSERT INTO app_user (user_id, user_name, status)
VALUES (2, 'suzuki', NULL);

NULL制約で止まる場合は ORA-01400 完全ガイド も確認してください。日付列のINSERTは INSERTで日付・日時を登録する完全ガイド が参考になります。

INSERT ALLで発生する例

Oracleで複数行をまとめてINSERTする時に INSERT ALL を使う場合、各 INTO 句ごとに列数と値数を合わせます。

bad-insert-all.sql
INSERT ALL
  INTO app_user (user_id, user_name, status) VALUES (1, 'tanaka')
  INTO app_user (user_id, user_name, status) VALUES (2, 'suzuki', 'ACTIVE')
SELECT * FROM dual;

-- 1つ目のINTO句だけ値が足りない
fixed-insert-all.sql
INSERT ALL
  INTO app_user (user_id, user_name, status) VALUES (1, 'tanaka', 'ACTIVE')
  INTO app_user (user_id, user_name, status) VALUES (2, 'suzuki', 'ACTIVE')
SELECT * FROM dual;

ビューやINVISIBLE列で起きるケース

ビューにINSERTする場合や、テーブルにINVISIBLE列がある場合も、列リストを明示しないINSERTは分かりにくくなります。ビュー側の列定義や、実テーブルの表示列/非表示列を確認してください。

check-view-columns.sql
SELECT column_id,
       column_name,
       data_type
FROM user_tab_columns
WHERE table_name = UPPER('&VIEW_OR_TABLE_NAME')
ORDER BY column_id;

テーブル定義や列制約の確認は CREATE TABLE完全ガイド も参考になります。

IDENTITY列・仮想列・DEFAULT列の注意点

自動採番のIDENTITY列、仮想列、DEFAULT値を持つ列がある場合は、列リストを明示すると安全です。自動で値を入れたい列は列リストから外し、明示的に入れる列だけを指定します。

identity-column-insert.sql
CREATE TABLE app_event (
  event_id NUMBER GENERATED BY DEFAULT AS IDENTITY,
  event_name VARCHAR2(100),
  created_at DATE DEFAULT SYSDATE
);

-- event_id と created_at は自動/DEFAULTに任せる
INSERT INTO app_event (event_name)
VALUES ('login');

自動採番列やDEFAULT列を列リストから外すと、値数のズレを避けやすくなります。逆に列リストへ含めるなら、その列に対応する値または DEFAULT を渡します。

列追加後に古いSQLで発生するケース

テーブルに列を追加した後、列リストを省略した古いINSERT文をそのまま実行すると、ORA-00947が発生しやすくなります。アプリ、バッチ、移行SQL、テストデータ作成SQLに列リスト省略のINSERTが残っていないか確認します。

old-insert-after-add-column.sql
-- もともと2列だったテーブルに status 列を追加した後
ALTER TABLE app_user ADD status VARCHAR2(20) DEFAULT 'ACTIVE' NOT NULL;

-- 古いSQL: 列リストなし、値は2つだけ
INSERT INTO app_user VALUES (1, 'tanaka');

-- 修正: 列リストを明示する
INSERT INTO app_user (user_id, user_name) VALUES (1, 'tanaka');

ORA-00913との違い

ORA-00947

値の個数が足りません。INSERT先の列数に対して、VALUESやSELECTの値が少ない状態です。

ORA-00913

値の個数が多すぎます。INSERT先の列数に対して、VALUESやSELECTの値が多い状態です。詳細は ORA-00913の原因と解決方法 を参照してください。

ORA-00936

式が不足している構文エラーです。カンマの後ろに式がない、SELECT句やWHERE句が壊れている場合などに発生します。詳細は ORA-00936の原因と解決方法 を参照してください。

ORA-00933

SQL文の終わり方や構文がOracleの形式に合っていない場合に発生します。複数行INSERTの書き方違いでも見かけます。詳細は ORA-00933の原因と解決方法 を参照してください。

SQL*LoaderやCSV取込では列対応を確認する

CSVや外部ファイルから投入する場合も、ファイル側の列数とテーブル側の列定義がずれると、値不足や別の取込エラーにつながります。大量データを扱うなら、INSERT文を手生成するよりSQL*Loaderなどを使う方が安全です。

SQL*Loaderの基本は SQL*Loader完全ガイド を参照してください。

修正の流れ

  1. INSERT先の列リストが明示されているか確認する
  2. 列リストがある場合は、列数とVALUESの値数を数える
  3. 列リストがない場合は、テーブル定義の列数・順番を確認する
  4. INSERT INTO ... SELECT なら、SELECT句の列数を確認する
  5. INSERT ALL なら、各INTO句の列数と値数を確認する
  6. 未指定でよい列は列リストから外す、または DEFAULT / NULL を明示する
  7. 列追加後に古いSQLを使っていないか、アプリ・バッチ・移行SQLを確認する

よくある質問

列リストを省略してもよいですか?

動く場合はありますが、実務ではおすすめしません。列追加や順番変更に弱く、ORA-00947や意図しない列ずれの原因になります。

DEFAULT値がある列にも値が必要ですか?

列リストから外せばDEFAULTが使われます。列リストに含めた場合は、値を渡すか DEFAULT を明示します。

IDENTITY列やシーケンス列でORA-00947になりますか?

列リストを省略していると、IDENTITY列を含む全列に対する値が必要になることがあります。自動採番列は列リストから外す形にすると安全です。

まとめ

ORA-00947は、INSERTで必要な値の数が足りない時に発生します。まずINSERT先の列リストと、VALUESまたはSELECTの値数が一致しているか確認してください。

最も安全な対策は、INSERTでは必ず列リストを明示することです。列追加やDEFAULT、NULL、INSERT INTO SELECT、INSERT ALLを使う場合も、列数と値数が1対1で対応しているかを確認すると、原因を素早く特定できます。

参考