【完全ガイド】ORA-00913: too many values の原因と解決方法|INSERT・サブクエリ・タプル比較 徹底解説
- 作成日 2026.08.10
- Oracle Database
Oracle 開発者が日常的に遭遇するINSERT エラー:
-- ❌ 列数 3、値の数 4
INSERT INTO employees(id, name, salary)
VALUES (100, 'John', 50000, 10);
-- ORA-00913: too many values
**「値が多すぎる」**というシンプルなメッセージ。ORA-00947(not enough values)の姉妹エラーで、対をなす存在です:
INSERT VALUESで値の数が列数より多いINSERT ... SELECTでサブクエリの列数超過WHERE A IN (SELECT A, B)のタプル比較(列数超過)HAVING A IN (SELECT A, B)の同様パターンCTAS後の列削除でずれるMERGE文のINSERT部分- スカラーサブクエリが複数列返す
EXISTSと**IN** の混同- 動的 SQLの生成ミス
- Rails マイグレーションでカラム削除後
このエラーはORA-00947 の裏返し、同じ原因メカニズムで**「多すぎる」**方向のミス:
CREATE TABLE t (a NUMBER, b NUMBER);
INSERT INTO t VALUES (1, 2, 3);
-- ORA-00913(2列に3値)
そして、タプル比較での典型:
-- ❌ 単一列に2列サブクエリ
SELECT * FROM employees
WHERE dept_id IN (SELECT dept_id, name FROM departments);
-- ORA-00913
多くの日本語記事が「値を減らせ」で終わりますが、実務では:
- 姉妹エラー3種(
ORA-00947,ORA-00913,ORA-01400)の厳密な区別 - スカラーサブクエリでの単一列制約
INvsEXISTSの使い分けCTAS後のカラム削除時の対処- MERGE 文の INSERT 節の落とし穴
- Rails / Java / Python からの防御的コーディング
- 列リスト明示による予防
- CI/CD パイプラインでの事前検出
さらに、知っておくべき「意外な発生パターン」:
-- スカラーサブクエリは 1 列 1 行のみ
SELECT emp_name,
(SELECT dept_id, dept_name FROM departments WHERE ...)
FROM employees;
-- ORA-00913(スカラーは 1 列のみ)
これは Oracle SQL の重要な制約で、日本語で本質的な解説がほぼない領域です。
本記事では、ORA-00913: too many values の完全な原因と解決方法を、リファレンスとして実用的に整理します。10大発生パターン、姉妹エラー ORA-00947/ORA-01400 との比較、5つの解決策、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で ORA-00913 を根本から解決できるようになります。
- 1. 結論:列数と値の数を一致させる
- 2. Oracle の INSERT ルール(復習)
- 3. 【原因①】INSERT VALUES で値過多(最頻出)
- 4. 【原因②】列リスト省略の罠(列削除後)
- 5. 【原因③】INSERT … SELECT の列過多
- 6. 【原因④】タプル比較の失敗(超危険)
- 7. 【原因⑤】スカラーサブクエリで複数列
- 8. 【原因⑥】CTAS 後の列削除
- 9. 【原因⑦】MERGE 文の INSERT 節
- 10. 【原因⑧】EXISTS と IN の混同
- 11. 【原因⑨】動的 SQL のミス
- 12. 【原因⑩】Rails マイグレーションで列削除
- 13. 5つの解決策 完全リファレンス
- 14. Rails / Java / Python 対応
- 15. 実践シナリオ
- 16. トラブルシューティング
- 17. よくある質問(FAQ)
- 18. 参考リンク
- 19. まとめ
結論:列数と値の数を一致させる
時間がない方向けに、最速の対処を先に示します。
エラーメッセージの読み方
ORA-00913: too many values
↑
値が多すぎる
= 期待される数より多い
期待される数:
- INSERT の列リスト(または全列)の数
- タプル
(A)の要素数 - スカラーサブクエリの列数(=1)
最速の診断
-- ① テーブルの列数確認
SELECT column_id, column_name, data_type
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
ORDER BY column_id;
-- ② サブクエリの列数
SELECT * FROM (
<サブクエリ>
) x WHERE 1=0;
5つの解決策
| # | 手法 | 使う場面 |
|---|---|---|
| ① | 列リスト明示 | INSERT の保守性 |
| ② | 値を減らす | 単純な過多 |
| ③ | サブクエリ列数調整 | INSERT SELECT / IN |
| ④ | EXISTS に変更 | 存在確認 |
| ⑤ | タプル要素一致 | 複数列 IN |
姉妹エラー3種
| エラー | 意味 |
|---|---|
| ORA-00947 | 値が足りない |
| ORA-00913 | 値が多すぎる |
| ORA-01400 | NOT NULL に NULL |
INSERT エラー3兄弟、対称的な関係。
詳細は以下で解説します。
Oracle の INSERT ルール(復習)
INSERT の基本構文
-- 列リスト明示
INSERT INTO t (col1, col2, col3) VALUES (v1, v2, v3);
-- 列数 = 値数 が必須
-- 列リスト省略
INSERT INTO t VALUES (v1, v2, v3);
-- テーブルの全列と同数の値が必要
スカラーサブクエリの制約
1 列 1 行のみ:
SELECT (SELECT dept_id FROM departments WHERE id = 10)
FROM DUAL;
-- OK: 1列
複数列は不可:
SELECT (SELECT dept_id, name FROM departments WHERE id = 10)
FROM DUAL;
-- ORA-00913
タプル比較
-- 単一列 IN は複数列サブクエリ不可
WHERE dept_id IN (SELECT dept_id FROM t); -- OK: 1列
WHERE dept_id IN (SELECT dept_id, name FROM t); -- ORA-00913
【原因①】INSERT VALUES で値過多(最頻出)
症状
CREATE TABLE employees (
id NUMBER,
name VARCHAR2(100),
salary NUMBER
);
-- ❌ 3列に4値
INSERT INTO employees(id, name, salary)
VALUES (100, 'John', 50000, 10);
-- ORA-00913
解決
A. 値を削除:
INSERT INTO employees(id, name, salary)
VALUES (100, 'John', 50000);
B. 列リスト拡張(列が存在すれば):
INSERT INTO employees(id, name, salary, dept_id)
VALUES (100, 'John', 50000, 10);
【原因②】列リスト省略の罠(列削除後)
症状
CREATE TABLE t (a NUMBER, b NUMBER, c NUMBER);
-- 動くコード
INSERT INTO t VALUES (1, 2, 3);
-- 列削除後
ALTER TABLE t DROP COLUMN c;
-- 既存の INSERT が壊れる
INSERT INTO t VALUES (1, 2, 3);
-- ORA-00913(2列に3値)
解決:常に列リスト明示
INSERT INTO t (a, b) VALUES (1, 2);
-- 列リスト明示で保守性向上
INSERT の値不足エラーの詳細は ORA-00947: not enough values の記事も参照してください。
【原因③】INSERT … SELECT の列過多
症状
CREATE TABLE dst (a NUMBER, b NUMBER);
CREATE TABLE src (a NUMBER, b NUMBER, c NUMBER);
-- ❌ SELECT が 3 列、INSERT は 2 列想定
INSERT INTO dst SELECT * FROM src;
-- ORA-00913
解決
A. 列リスト明示:
INSERT INTO dst (a, b) SELECT a, b FROM src;
B. 全列指定:
INSERT INTO dst SELECT a, b FROM src;
C. dst に列追加(もし想定される場合):
ALTER TABLE dst ADD (c NUMBER);
INSERT INTO dst SELECT * FROM src;
【原因④】タプル比較の失敗(超危険)
症状
-- ❌ 単一列 IN に複数列サブクエリ
SELECT * FROM employees
WHERE dept_id IN (SELECT dept_id, name FROM departments);
-- ORA-00913
解決
A. サブクエリを1列に:
SELECT * FROM employees
WHERE dept_id IN (SELECT dept_id FROM departments);
B. タプル比較に:
SELECT * FROM employees
WHERE (dept_id, name) IN (SELECT dept_id, name FROM departments);
-- 両側 2 列で一致
HAVING でも同様
-- ❌
SELECT dept_id, COUNT(*) FROM employees
GROUP BY dept_id
HAVING dept_id IN (SELECT dept_id, name FROM departments);
-- ORA-00913
【原因⑤】スカラーサブクエリで複数列
症状
-- ❌ スカラー位置に複数列
SELECT emp_id,
(SELECT dept_id, dept_name FROM departments WHERE ...)
FROM employees;
-- ORA-00913
解決
A. 個別サブクエリ:
SELECT emp_id,
(SELECT dept_id FROM departments WHERE ...) AS dept_id,
(SELECT dept_name FROM departments WHERE ...) AS dept_name
FROM employees;
B. JOIN に変更(推奨):
SELECT e.emp_id, d.dept_id, d.dept_name
FROM employees e
LEFT JOIN departments d ON d.id = e.dept_id;
【原因⑥】CTAS 後の列削除
シナリオ
-- 元テーブル
CREATE TABLE src (a NUMBER, b NUMBER, c NUMBER);
-- CTAS
CREATE TABLE dst AS SELECT * FROM src;
-- dst も 3 列
-- dst の列削除
ALTER TABLE dst DROP COLUMN c;
-- 既存の INSERT が壊れる
INSERT INTO dst SELECT * FROM src;
-- ORA-00913
解決
INSERT INTO dst (a, b) SELECT a, b FROM src;
【原因⑦】MERGE 文の INSERT 節
症状
MERGE INTO dst USING src ON (dst.id = src.id)
WHEN NOT MATCHED THEN
INSERT (id, name) VALUES (src.id, src.name, src.salary);
-- ORA-00913(2列に3値)
解決
MERGE INTO dst USING src ON (dst.id = src.id)
WHEN NOT MATCHED THEN
INSERT (id, name, salary) VALUES (src.id, src.name, src.salary);
-- 列リストに salary 追加
MERGE の詳細は Oracle MERGE 文 使い方の記事も参照してください。
【原因⑧】EXISTS と IN の混同
症状
-- ❌ EXISTS の中の SELECT 列は意味ない(NULL でもOK)
-- が、IN と混同して:
SELECT * FROM employees
WHERE dept_id IN (
SELECT 1 FROM departments WHERE id = 10
);
-- 動くが意図と違う
-- 逆に、EXISTS を IN のように書くとエラー
SELECT * FROM employees
WHERE dept_id EXISTS (SELECT dept_id, name FROM departments);
-- 構文エラー
解決
IN と EXISTS の正しい使い分け:
-- IN: 値の一致
WHERE dept_id IN (SELECT dept_id FROM departments);
-- EXISTS: 存在確認(相関)
WHERE EXISTS (
SELECT 1 FROM departments d
WHERE d.dept_id = employees.dept_id
);
【原因⑨】動的 SQL のミス
症状
DECLARE
v_cols VARCHAR2(100) := 'id, name'; -- 2列
v_vals VARCHAR2(100) := ':1, :2, :3'; -- 3値
BEGIN
EXECUTE IMMEDIATE
'INSERT INTO t (' || v_cols || ') VALUES (' || v_vals || ')'
USING 100, 'John', 50000;
-- ORA-00913
END;
/
解決
動的 SQL 前に列/値数チェック:
DECLARE
v_col_count PLS_INTEGER;
v_val_count PLS_INTEGER;
BEGIN
v_col_count := REGEXP_COUNT(v_cols, ',') + 1;
v_val_count := REGEXP_COUNT(v_vals, ',') + 1;
IF v_col_count != v_val_count THEN
RAISE_APPLICATION_ERROR(-20001, '列数と値数不一致');
END IF;
END;
/
【原因⑩】Rails マイグレーションで列削除
シナリオ
# Rails migration
class RemoveDeptFromUsers < ActiveRecord::Migration[8.0]
def change
remove_column :users, :dept_id
end
end
その後、生 SQL で INSERT していると:
# ❌ 削除された列を含む
ActiveRecord::Base.connection.execute(
"INSERT INTO users (id, name, dept_id) VALUES (1, 'John', 10)"
)
-- ORA-00913
解決
A. ActiveRecord 使用:
User.create!(id: 1, name: 'John')
B. 列リスト更新:
execute "INSERT INTO users (id, name) VALUES (1, 'John')"
Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、rails db:migrate 使い方の記事、pending migration エラーの記事も参照してください。
5つの解決策 完全リファレンス
解決策① 列リスト明示(推奨)
-- ✅ 常に列リスト
INSERT INTO t (col1, col2) VALUES (v1, v2);
-- ❌ 列リスト省略は危険
INSERT INTO t VALUES (v1, v2);
解決策② 値を減らす
INSERT INTO t (a, b) VALUES (1, 2);
-- 3値だったのを2値に
解決策③ サブクエリ列数調整
-- 列数を合わせる
INSERT INTO dst (a, b) SELECT a, b FROM src;
-- IN の複数列は タプル比較
WHERE (a, b) IN (SELECT c1, c2 FROM t);
解決策④ EXISTS に変更
-- 存在確認は EXISTS
WHERE EXISTS (
SELECT 1 FROM t
WHERE t.id = main.id
);
解決策⑤ タプル要素一致
-- 両側同じ列数
WHERE (a, b, c) IN (SELECT c1, c2, c3 FROM t);
Rails / Java / Python 対応
Rails ActiveRecord
基本:
# ✅ ActiveRecord は自動処理
User.create!(id: 1, name: 'John')
# エラーハンドリング
begin
User.create!(attributes)
rescue ActiveRecord::StatementInvalid => e
if e.message.include?("ORA-00913")
Rails.logger.error "値過多: #{e.message}"
end
end
Java (JDBC)
// ✅ PreparedStatement + 列リスト
PreparedStatement ps = conn.prepareStatement(
"INSERT INTO users (id, name) VALUES (?, ?)"
);
ps.setInt(1, 1);
ps.setString(2, "John");
ps.executeUpdate();
// エラーハンドリング
try {
ps.executeUpdate();
} catch (SQLException e) {
if (e.getErrorCode() == 913) {
logger.error("値過多: " + e.getMessage());
}
}
Python (oracledb)
import oracledb
# ✅ 列リスト明示
cursor.execute("""
INSERT INTO users (id, name) VALUES (:1, :2)
""", (1, 'John'))
# エラーハンドリング
try:
cursor.execute(sql, params)
except oracledb.DatabaseError as e:
error_obj, = e.args
if error_obj.code == 913:
print(f"値過多: {error_obj.message}")
実践シナリオ
シナリオ1:CTAS 後の列削除運用
-- 1. テーブル作成
CREATE TABLE report AS
SELECT id, name, amount, region FROM orders WHERE 1=0;
-- 2. データ投入(列リスト明示)
INSERT INTO report (id, name, amount, region)
SELECT id, name, amount, region FROM orders;
-- 3. 列削除
ALTER TABLE report DROP COLUMN region;
-- 4. 既存 INSERT を修正
INSERT INTO report (id, name, amount)
SELECT id, name, amount FROM orders;
シナリオ2:ETL パイプラインでの防御
CREATE OR REPLACE PROCEDURE etl_load IS
v_col_count PLS_INTEGER;
BEGIN
SELECT COUNT(*) INTO v_col_count
FROM user_tab_columns
WHERE table_name = 'DST';
IF v_col_count != 2 THEN
RAISE_APPLICATION_ERROR(-20001,
'想定と列数不一致: ' || v_col_count);
END IF;
INSERT INTO dst (a, b) SELECT a, b FROM src;
END;
/
シナリオ3:タプル比較の適切な使用
-- 複数列の一致検索
SELECT * FROM orders
WHERE (customer_id, order_date) IN (
SELECT customer_id, MAX(order_date)
FROM orders
GROUP BY customer_id
);
-- 各顧客の最新注文
シナリオ4:Rails でのモデル対応
class User < ApplicationRecord
# スキーマ変更に強い
# ActiveRecord が列名を自動処理
end
# ✅ 属性ハッシュで作成
User.create!(attributes.slice(*User.column_names))
シナリオ5:Data Pump インポート
# 列不一致の事前確認
impdp system/pw dumpfile=data.dmp SQLFILE=preview.sql
# preview.sql を目視、列数チェック
Data Pump の詳細は Oracle Data Pump 使い方の記事も参照してください。
シナリオ6:MERGE での列一致
MERGE INTO users u
USING (
SELECT 1 AS id, 'John' AS name, 100 AS salary FROM DUAL
) s ON (u.id = s.id)
WHEN NOT MATCHED THEN
INSERT (id, name, salary)
VALUES (s.id, s.name, s.salary);
-- 列数と値数を同数に
シナリオ7:Java Spring での対処
@Repository
public class UserRepo {
public void insertUser(User user) {
String sql = """
INSERT INTO users (id, name, salary)
VALUES (?, ?, ?)
""";
jdbc.update(sql,
user.getId(),
user.getName(),
user.getSalary()
);
}
}
シナリオ8:Python での動的 INSERT
def insert_row(cursor, table: str, data: dict):
columns = list(data.keys())
placeholders = [f":{i+1}" for i in range(len(columns))]
sql = f"""
INSERT INTO {table} ({', '.join(columns)})
VALUES ({', '.join(placeholders)})
"""
cursor.execute(sql, list(data.values()))
シナリオ9:Docker Oracle でのテスト
docker exec -it oracle-xe sqlplus scott/tiger <<EOF
CREATE TABLE t (a NUMBER, b NUMBER);
-- ORA-00913
INSERT INTO t VALUES (1, 2, 3);
-- OK
INSERT INTO t (a, b) VALUES (1, 2);
EOF
Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。
シナリオ10:CI/CD スキーマ検証
- name: Check schema consistency
run: |
sqlplus -s $DB_USER/$DB_PW <<EOF
SELECT table_name, COUNT(*) col_count
FROM user_tab_columns
GROUP BY table_name;
EOF
Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。
トラブルシューティング
列削除後のトラブル
カラム削除で既存 INSERT が壊れた:
-- 影響範囲確認
SELECT * FROM user_source
WHERE UPPER(text) LIKE '%INSERT INTO T%';
-- 全 PL/SQL コードを検索
動的 SQL のデバッグ
DBMS_OUTPUT.PUT_LINE('SQL: ' || v_sql);
CTAS で列がずれた
SELECT column_id, column_name
FROM user_tab_columns
WHERE table_name IN ('SRC', 'DST')
ORDER BY table_name, column_id;
PostgreSQL からの移行
PG では INSERT … RETURNING * が使える。Oracle は個別変数指定。
JOIN で自己参照
自己 JOIN 時のエイリアス漏れ:
-- ❌ エイリアスなし
SELECT * FROM t, t WHERE ...;
-- ✅
SELECT * FROM t a, t b WHERE ...;
スカラーサブクエリの制限
1列1行、複数列返さない:
-- ❌
SELECT (SELECT a, b FROM t WHERE id = 1) FROM DUAL;
-- ✅
SELECT (SELECT a FROM t WHERE id = 1),
(SELECT b FROM t WHERE id = 1)
FROM DUAL;
よくある質問(FAQ)
Q1. ORA-00913 と ORA-00947 の違い
- 00913: 値が多すぎる
- 00947: 値が足りない
Q2. ORA-01400 との違い
- 01400: NOT NULL 列に NULL
- 00913: 列数と値数の不一致
Q3. 列リスト明示のメリット
- テーブル変更に強い
- 保守性向上
- 意図が明確
Q4. Rails での対応
ActiveRecord::Base は自動で列名処理。
Q5. タプル比較の使い所
複数列の一致検索。両側同じ要素数。
Q6. スカラーサブクエリの制約
1 列 1 行のみ。複数列は個別 or JOIN。
Q7. EXISTS と IN の違い
- IN: 値の一致(複数値可)
- EXISTS: 存在確認(相関)
Q8. 動的 SQL
生成 SQL を出力して確認。
Q9. 列削除時の影響
列リスト明示なら影響なし。省略なら要修正。
Q10. パフォーマンスへの影響
構文エラーは実行前、パフォーマンス影響なし。
Q11. 予防策
- 列リスト明示
- CI/CD でスキーマ検証
- コードレビュー
Q12. 23ai の新機能
INSERT WHEN NOT EXISTS 対応(一部)。
参考リンク
Oracle 公式
- Oracle Database Error Messages: ORA-00913
- Oracle Database SQL Language Reference: INSERT
- Oracle Database SQL Language Reference: Subqueries
- Oracle Database SQL Language Reference: MERGE
まとめ
ORA-00913: too many values の要点を再整理します。
エラーの本質
SQL 文で期待される値の数より
実際の値の数が多い
→ INSERT / タプル比較 / スカラーサブクエリ
エラーメッセージの読み方
ORA-00913: too many values
↑
期待より値が多い
INSERT エラー3兄弟
| エラー | 意味 |
|---|---|
| ORA-00913 | 値が多すぎる |
| ORA-00947 | 値が足りない |
| ORA-01400 | NOT NULL に NULL |
10大原因
| # | 原因 | 対処 |
|---|---|---|
| ① | INSERT VALUES 値過多 | 値削除 or 列拡張 |
| ② | 列リスト省略 + 列削除 | 列リスト明示 |
| ③ | INSERT SELECT 列過多 | 列合わせ |
| ④ | タプル比較 過多 | サブクエリ列数 |
| ⑤ | スカラー複数列 | 個別 or JOIN |
| ⑥ | CTAS 後の列削除 | 列リスト明示 |
| ⑦ | MERGE INSERT | 全列指定 |
| ⑧ | EXISTS/IN 混同 | 正しい使い分け |
| ⑨ | 動的 SQL | 生成確認 |
| ⑩ | Rails migration 後 | ActiveRecord |
5つの解決策
-- ① 列リスト明示(推奨)
INSERT INTO t (a, b) VALUES (1, 2);
-- ② 値削減
INSERT INTO t (a, b) VALUES (1, 2);
-- ③ サブクエリ列数調整
INSERT INTO dst (a, b) SELECT a, b FROM src;
-- ④ EXISTS 使用
WHERE EXISTS (SELECT 1 FROM t WHERE ...);
-- ⑤ タプル要素一致
WHERE (a, b) IN (SELECT c1, c2 FROM t);
診断クエリ
-- ① 列構造確認
SELECT column_id, column_name, data_type
FROM user_tab_columns
WHERE table_name = 'T'
ORDER BY column_id;
-- ② サブクエリ列数
SELECT * FROM (<subquery>) WHERE 1=0;
スカラーサブクエリの制約
-- ❌ 複数列
(SELECT a, b FROM t WHERE id = 1)
-- ✅ 単一列
(SELECT a FROM t WHERE id = 1)
タプル比較
-- 両側同じ要素数
WHERE (a, b) IN (SELECT c1, c2 FROM t);
-- 単一列
WHERE a IN (SELECT c1 FROM t);
IN vs EXISTS
-- IN: 値の集合との比較
WHERE dept_id IN (SELECT dept_id FROM departments);
-- EXISTS: 相関サブクエリの存在確認
WHERE EXISTS (
SELECT 1 FROM departments d
WHERE d.dept_id = employees.dept_id
);
予防のポイント
1. INSERT には必ず列リスト明示
2. INSERT SELECT でも列を明示
3. Rails: ActiveRecord 使用
4. Java: PreparedStatement + 列リスト
5. Python: バインド変数 + 列リスト
6. CI/CD でスキーマ検証
7. 列削除時は既存 SQL 確認
8. Data Pump は SQLFILE で事前確認
9. コードレビューで INSERT 確認
10. スカラーサブクエリは 1 列 1 行を意識
これらの知識は、Oracle でのアプリ開発・ETL パイプライン・マイグレーション設計・Rails / Java / Python 開発・データ移行・CTAS 運用・CI/CD 検証など、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-00913 に出会っても冷静に的確に対処できるようになります。
本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。
-
前の記事
【完全ガイド】ORA-00933: SQL command not properly ended の原因と解決方法|UPDATE JOIN・INSERT ORDER BY・MySQL 移行 徹底解説 2026.08.07
-
次の記事
【完全ガイド】PLS-00201: identifier must be declared の原因と解決方法|ロール経由権限の罠・DBMS_LOCK・シノニム 徹底解説 2026.08.12
コメントを書く