OracleデータベースでカラムのNOT NULL制約を削除・追加したいと思ったことはありませんか?
テーブル設計の変更やデータ移行の際に、NOT NULL制約の操作は頻繁に必要になります。しかし、構文を間違えると ORA-01451 や ORA-02296 などのエラーが発生し、意図しないデータ不整合を招く恐れもあります。
この記事では、NOT NULL制約の削除・追加の基本構文から、複数カラムの一括変更、DEFAULT制約との組み合わせ、制約の確認方法、他RDBMS(MySQL・PostgreSQL・SQL Server)との構文比較まで、実務で使える知識を網羅的に解説します。
NOT NULL制約とは
NOT NULL制約は、カラムに NULL(値なし)を格納することを禁止する制約です。
ポイント:NOT NULL制約が設定されたカラムには、INSERT時に必ず値を指定する必要があります。DEFAULT値が設定されている場合は、省略してもDEFAULT値が格納されます。
テーブル作成時にNOT NULL制約を設定する例を見てみましょう。
SQL
CREATE TABLE employees (
emp_id NUMBER NOT NULL,
emp_name VARCHAR2(100) NOT NULL,
email VARCHAR2(200),
dept_id NUMBER
);
この例では emp_id と emp_name にNOT NULL制約が設定されています。email と dept_id はNULLを許可しています。
NOT NULL制約を削除する方法(基本構文)
OracleでNOT NULL制約を削除するには、ALTER TABLE ... MODIFY 文を使います。
構文
ALTER TABLE テーブル名 MODIFY (カラム名 NULL);
注意:OracleではMySQLやSQL Serverと異なり、ALTER TABLE ... ALTER COLUMN 構文は使えません。必ず MODIFY を使用してください。
実行例:emp_nameのNOT NULLを削除
SQL
-- emp_nameカラムからNOT NULL制約を削除
ALTER TABLE employees MODIFY (emp_name NULL);
これで emp_name カラムにNULLを格納できるようになります。
変更前後の確認
制約が正しく削除されたか確認するために、変更前後で DESCRIBE を実行しましょう。
変更前
Name Null? Type
--------- -------- -------------
EMP_ID NOT NULL NUMBER
EMP_NAME NOT NULL VARCHAR2(100)
EMAIL VARCHAR2(200)
DEPT_ID NUMBER
変更後
Name Null? Type
--------- -------- -------------
EMP_ID NOT NULL NUMBER
EMP_NAME VARCHAR2(100)
EMAIL VARCHAR2(200)
DEPT_ID NUMBER
EMP_NAME の Null? 欄から NOT NULL が消えていれば成功です。
複数カラムのNOT NULLを一括削除する
複数のカラムからNOT NULL制約を同時に削除できます。カラムをカンマで区切って指定します。
SQL
-- 複数カラムのNOT NULLを一括削除
ALTER TABLE employees MODIFY (
emp_name NULL,
email NULL
);
ポイント:1つの ALTER TABLE 文で複数カラムを同時に変更できるため、カラムごとに個別のSQLを実行する必要はありません。DDLの実行回数を減らすことでパフォーマンスにも有利です。
NOT NULL制約を追加する方法
逆に、NULLを許可しているカラムにNOT NULL制約を追加する方法です。
構文
ALTER TABLE テーブル名 MODIFY (カラム名 NOT NULL);
実行例:emailにNOT NULLを追加
SQL
-- emailカラムにNOT NULL制約を追加
ALTER TABLE employees MODIFY (email NOT NULL);
注意:カラムに既にNULLデータが存在する場合、NOT NULL制約の追加は ORA-02296 エラーで失敗します。事前にNULLデータを更新または削除してください。
NULLデータが存在する場合の対処法
SQL
-- 手順1: NULLデータを確認
SELECT COUNT(*) FROM employees WHERE email IS NULL;
-- 手順2: NULLデータをデフォルト値で更新
UPDATE employees SET email = 'unknown@example.com'
WHERE email IS NULL;
-- 手順3: NOT NULL制約を追加
ALTER TABLE employees MODIFY (email NOT NULL);
DEFAULT制約との組み合わせ
NOT NULL制約は DEFAULT 値と組み合わせて使うことが多いです。DEFAULT値を設定しておくことで、INSERT時にカラムを省略してもNOT NULL違反を防げます。
NOT NULL + DEFAULT の設定
SQL
-- DEFAULT値とNOT NULLを同時に設定
ALTER TABLE employees MODIFY (
status DEFAULT 'active' NOT NULL
);
NOT NULL削除時のDEFAULTの扱い
NOT NULL制約を削除しても、DEFAULT値はそのまま残ります。
SQL
-- NOT NULLだけを削除(DEFAULT値は維持される)
ALTER TABLE employees MODIFY (status NULL);
-- DEFAULT値も削除したい場合
ALTER TABLE employees MODIFY (status DEFAULT NULL NULL);
DEFAULT値の確認方法
USER_TAB_COLUMNS の DATA_DEFAULT カラムで確認できます
- NOT NULL制約を削除してもDEFAULT値は独立して保持されます
- DEFAULT値の変更は
ALTER TABLE ... MODIFY (カラム名 DEFAULT 新しい値) で行います
制約の確認方法
NOT NULL制約の状態を確認する方法はいくつかあります。
方法1:DESCRIBEコマンド
最もシンプルな確認方法です。SQL*PlusやSQL Developerで使用できます。
SQL*Plus
DESCRIBE employees;
-- または省略形
DESC employees;
実行結果
Name Null? Type
--------- -------- -------------
EMP_ID NOT NULL NUMBER
EMP_NAME NOT NULL VARCHAR2(100)
EMAIL VARCHAR2(200)
DEPT_ID NUMBER
方法2:USER_TAB_COLUMNSビュー
SQLで制約を確認する場合は USER_TAB_COLUMNS(または ALL_TAB_COLUMNS)を使います。
SQL
-- 特定テーブルのカラムのNULL許可状態を確認
SELECT column_name,
data_type,
nullable,
data_default
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
ORDER BY column_id;
実行結果
COLUMN_NAME DATA_TYPE NULLABLE DATA_DEFAULT
----------- ------------ -------- ------------
EMP_ID NUMBER N
EMP_NAME VARCHAR2 N
EMAIL VARCHAR2 Y
DEPT_ID NUMBER Y
| NULLABLEの値 |
意味 |
N |
NOT NULL制約あり(NULLを許可しない) |
Y |
NULL許可(NOT NULL制約なし) |
方法3:USER_CONSTRAINTSビュー
名前付きのNOT NULL制約を確認する場合は、制約ビューを使います。
SQL
-- NOT NULL制約(CHECK制約として登録される)を確認
SELECT c.constraint_name,
cc.column_name,
c.search_condition
FROM user_constraints c
JOIN user_cons_columns cc
ON c.constraint_name = cc.constraint_name
WHERE c.table_name = 'EMPLOYEES'
AND c.constraint_type = 'C'
ORDER BY cc.column_name;
NOT NULL制約はCHECK制約の一種
- OracleではNOT NULL制約は内部的に
CHECK (column IS NOT NULL) として管理されます
USER_CONSTRAINTS では constraint_type = 'C'(CHECK制約)として表示されます
- 制約名はシステムが自動生成(例:
SYS_C00xxxx)されます
名前付きNOT NULL制約の操作
NOT NULL制約に名前を付けて定義することもできます。名前付き制約は管理がしやすくなります。
名前付き制約の作成
SQL
-- テーブル作成時に名前付きNOT NULL制約を定義
CREATE TABLE products (
product_id NUMBER CONSTRAINT pk_product_nn NOT NULL,
product_name VARCHAR2(200) CONSTRAINT name_nn NOT NULL,
price NUMBER
);
-- 既存テーブルに名前付きNOT NULL制約を追加
ALTER TABLE products MODIFY (
price CONSTRAINT price_nn NOT NULL
);
名前付き制約の削除
名前付きの場合は、DROP CONSTRAINT でも削除できます。
SQL
-- 方法1: MODIFY NULL で削除(推奨)
ALTER TABLE products MODIFY (price NULL);
-- 方法2: 制約名を指定して削除
ALTER TABLE products DROP CONSTRAINT price_nn;
ポイント:MODIFY NULL のほうが制約名を調べる必要がなくシンプルです。DROP CONSTRAINT は、制約名がわかっている場合やスクリプトで管理している場合に使います。
他のRDBMSとの構文比較
NOT NULL制約の削除構文はRDBMSによって異なります。
| RDBMS |
NOT NULL削除の構文 |
| Oracle |
ALTER TABLE t MODIFY (col NULL) |
| MySQL |
ALTER TABLE t MODIFY col データ型 NULL |
| PostgreSQL |
ALTER TABLE t ALTER COLUMN col DROP NOT NULL |
| SQL Server |
ALTER TABLE t ALTER COLUMN col データ型 NULL |
各RDBMSのサンプルコード
MySQL の場合
MySQL
-- MySQLではデータ型の再指定が必要
ALTER TABLE employees MODIFY emp_name VARCHAR(100) NULL;
-- NOT NULLの追加
ALTER TABLE employees MODIFY emp_name VARCHAR(100) NOT NULL;
PostgreSQL の場合
PostgreSQL
-- PostgreSQLではALTER COLUMN ... DROP NOT NULLを使う
ALTER TABLE employees ALTER COLUMN emp_name DROP NOT NULL;
-- NOT NULLの追加
ALTER TABLE employees ALTER COLUMN emp_name SET NOT NULL;
SQL Server の場合
SQL Server
-- SQL ServerではALTER COLUMNを使う
ALTER TABLE employees ALTER COLUMN emp_name NVARCHAR(100) NULL;
-- NOT NULLの追加
ALTER TABLE employees ALTER COLUMN emp_name NVARCHAR(100) NOT NULL;
Oracle固有の注意点
- Oracleでは
MODIFY を使い、括弧 () でカラムを囲みます
- MySQL / SQL Server のように データ型の再指定は不要 です
- PostgreSQLのような
DROP NOT NULL / SET NOT NULL 構文はありません
よくあるエラーと対処法
NOT NULL制約の操作で発生しやすいエラーを整理します。
| エラー |
原因 |
対処法 |
ORA-02296 |
NULLデータが存在する状態でNOT NULLを追加しようとした |
NULLデータを更新または削除してから実行 |
ORA-01451 |
既にNULL許可のカラムに対して NULL を再指定した |
先にNULLABLEを確認してから実行 |
ORA-01400 |
NOT NULLカラムにNULLをINSERTしようとした |
値を指定するか、DEFAULT値を設定 |
ORA-01407 |
NOT NULLカラムをNULLにUPDATEしようとした |
NULL以外の値を指定 |
ORA-00942 |
テーブルが存在しない、またはアクセス権がない |
テーブル名・スキーマを確認 |
ORA-02296 の詳細と対処
NOT NULLを追加する際に最も多いエラーです。
エラー再現と対処
-- NULLデータが入っている状態でNOT NULLを追加
ALTER TABLE employees MODIFY (email NOT NULL);
-- ORA-02296: (SCOTT.) の使用可能化 - NULLが見つかりました
-- 対処1: NULLの件数を確認
SELECT COUNT(*) AS null_count
FROM employees
WHERE email IS NULL;
-- 対処2: NULLデータを適切な値で埋める
UPDATE employees
SET email = 'N/A'
WHERE email IS NULL;
COMMIT;
-- 対処3: 再度NOT NULLを追加
ALTER TABLE employees MODIFY (email NOT NULL);
ORA-01451 の詳細と対処
既にNULLを許可しているカラムに再度 NULL を指定すると発生します。
エラー再現と対処
-- 既にNULL許可のカラムにNULLを指定
ALTER TABLE employees MODIFY (email NULL);
-- ORA-01451: 列はすでにNULL可能です
-- 対処: 事前にNULLABLEを確認
SELECT column_name, nullable
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
AND column_name = 'EMAIL';
実務での注意点
本番環境でNOT NULL制約を操作する際は、以下の点に注意してください。
1. 既存データへの影響
注意:NOT NULL制約を削除する場合、既存データには影響しません。しかし、削除後に新規INSERTでNULLが入る可能性があるため、アプリケーション側のバリデーションを確認してください。
2. ALTER TABLE は DDL(暗黙コミット)
注意点
-- ALTER TABLEはDDLのため、暗黙的にCOMMITされる
-- 以下のようなトランザクション内での使用に注意
UPDATE employees SET salary = 50000 WHERE emp_id = 1;
-- ↓ この時点でUPDATEも一緒にCOMMITされる
ALTER TABLE employees MODIFY (email NULL);
-- ROLLBACKしてもUPDATEは取り消せない
ROLLBACK; -- 効果なし
3. ロックへの影響
ALTER TABLE実行時のロック
ALTER TABLE ... MODIFY は対象テーブルに排他ロック(DDLロック)をかけます
- 他のセッションからの DML(INSERT/UPDATE/DELETE)はブロックされます
- 大量レコードのテーブルでは、メンテナンスウィンドウで実行することを推奨します
- Oracle 11g以降では
DBMS_REDEFINITION を使ったオンライン変更も可能です
4. 本番運用でのベストプラクティス
| 手順 |
内容 |
| 1. 事前確認 |
対象カラムの現在のNULL許可状態を確認 |
| 2. データ確認 |
NULLデータの有無と件数を確認(NOT NULL追加時) |
| 3. バックアップ |
テーブルのバックアップを取得 |
| 4. テスト環境で検証 |
本番適用前にテスト環境で動作確認 |
| 5. 本番実行 |
メンテナンスウィンドウ中に実行 |
| 6. 事後確認 |
制約変更後のテーブル構造を確認 |
本番運用のサンプルスクリプト
本番用スクリプト例
-- ============================================
-- NOT NULL制約 変更スクリプト
-- 対象: employees.email
-- 変更内容: NOT NULL → NULL許可
-- ============================================
-- 1. 変更前の状態を確認
SELECT column_name, nullable, data_default
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
AND column_name = 'EMAIL';
-- 2. NOT NULL制約を削除
ALTER TABLE employees MODIFY (email NULL);
-- 3. 変更後の状態を確認
SELECT column_name, nullable, data_default
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
AND column_name = 'EMAIL';
よく使う操作のまとめ
| 操作 |
SQL構文 |
| NOT NULL削除 |
ALTER TABLE t MODIFY (col NULL) |
| NOT NULL追加 |
ALTER TABLE t MODIFY (col NOT NULL) |
| 一括削除 |
ALTER TABLE t MODIFY (col1 NULL, col2 NULL) |
| DEFAULT付きNOT NULL |
ALTER TABLE t MODIFY (col DEFAULT '値' NOT NULL) |
| 名前付き制約で削除 |
ALTER TABLE t DROP CONSTRAINT 制約名 |
| NULL状態の確認 |
SELECT nullable FROM user_tab_columns WHERE ... |
まとめ
| 項目 |
内容 |
| NOT NULL削除 |
ALTER TABLE テーブル名 MODIFY (カラム名 NULL) |
| NOT NULL追加 |
ALTER TABLE テーブル名 MODIFY (カラム名 NOT NULL) |
| NULLデータに注意 |
NOT NULL追加前にNULLデータが存在しないことを確認 |
| DDLの暗黙コミット |
ALTER TABLE は自動コミットされるため、ROLLBACKできない |
| 確認方法 |
DESC テーブル名 または USER_TAB_COLUMNS ビュー |
NOT NULL制約の操作はOracleの基本スキルですが、本番環境では暗黙コミットやロックの影響を理解した上で慎重に実行しましょう。変更前のバックアップと事後確認を忘れずに行うことが大切です。