Oracleでテーブルを作成するには CREATE TABLE 文を使います。MySQLや PostgreSQL と基本的な考え方は同じですが、Oracle 独自のデータ型(VARCHAR2・NUMBER)や制約の書き方、表領域(TABLESPACE)の指定など、押さえておくべき違いがいくつかあります。
特に「制約をCREATE TABLE内に書くか、後から ALTER TABLE で追加するか」や、「既存テーブルをコピーして新しいテーブルを作る CTAS」は実務でよく使うにもかかわらず、初心者がつまずきやすいポイントです。
この記事では、基本構文と主要データ型から、PRIMARY KEY・FOREIGN KEY・CHECK などの制約の書き方、CTAS(CREATE TABLE AS SELECT)によるテーブルコピー、表領域の指定方法まで体系的に解説します。
・CREATE TABLE の完全な構文
・Oracle の主要データ型(NUMBER / VARCHAR2 / DATE / TIMESTAMP / CLOB / BLOB)の使い分け
・PRIMARY KEY / FOREIGN KEY / UNIQUE / NOT NULL / CHECK / DEFAULT 制約の書き方
・インライン制約とテーブルレベル制約の違い
・CTAS(CREATE TABLE AS SELECT)でテーブルを複製する方法
・表領域(TABLESPACE)を指定してテーブルを作成する方法
・テーブル作成後の確認 SQL
・CREATE TABLE に必要な権限
CREATE TABLE の基本構文
テーブルを作成する基本的な構文は以下のとおりです。
CREATE TABLE テーブル名 (
列名1 データ型 [DEFAULT デフォルト値] [列レベル制約],
列名2 データ型 [DEFAULT デフォルト値] [列レベル制約],
...
[テーブルレベル制約]
)
[TABLESPACE 表領域名];
最もシンプルな例として、社員テーブルを作成してみます。
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
emp_name VARCHAR2(100) NOT NULL,
dept_id NUMBER(5),
salary NUMBER(10, 2),
hire_date DATE DEFAULT SYSDATE,
CONSTRAINT pk_emp PRIMARY KEY (emp_id)
);
テーブル名・列名の命名規則
| ルール | 内容 |
|---|---|
| 先頭文字 | 英字で始めること(数字・記号はNG) |
| 使用できる文字 | 英字・数字・_(アンダースコア)・$・# |
| 最大文字数 | 30文字(Oracle 12.2以降は128文字) |
| 大文字・小文字 | 引用符なしで作成すると内部的に大文字で格納される |
| 予約語 | SELECT・TABLE・WHERE などのSQL予約語は使えない |
| 同一スキーマ内での一意性 | 同じスキーマ内に同名テーブルは作成できない |
・テーブル名は複数形または単数形で統一する(例:
EMP / EMPLOYEES)・スネークケース(
ORDER_DETAIL)が一般的・列名も一貫性を持たせる(例: ID列は
テーブル名_ID で統一)・略語を使う場合はプロジェクト内で統一する
Oracle の主要データ型
Oracle 独自のデータ型を正しく使い分けることがパフォーマンスとデータ品質の基本です。
文字型
| データ型 | 説明 | 最大サイズ | 使い分け |
|---|---|---|---|
| VARCHAR2(n) | 可変長文字列 | 4000バイト(拡張なし) | 氏名・住所・説明文など可変長の文字列全般 |
| CHAR(n) | 固定長文字列(空白埋め) | 2000バイト | 都道府県コード・区分コードなど固定長のコード値 |
| NVARCHAR2(n) | Unicode可変長文字列 | 4000バイト | 多言語対応が必要な場合 |
| CLOB | 大容量文字データ | 最大128TB | 長文テキスト・HTMLコンテンツ・JSONデータ |
Oracle にも
VARCHAR 型はありますが、将来的な仕様変更が示唆されているため使用を避け、代わりに VARCHAR2 を使うことが Oracle の公式推奨です。数値型
| データ型 | 説明 | 使い分け |
|---|---|---|
| NUMBER(p, s) | 固定小数点数。p=全体桁数、s=小数桁数 | 金額・数量・割合など。p=10,s=2 で整数8桁・小数2桁 |
| NUMBER | 精度・スケール指定なし | 整数(IDなど)。内部的に可変長で格納 |
| INTEGER | NUMBER(38)の別名 | 整数専用(互換性のため使用可) |
| FLOAT(p) | 浮動小数点数 | 科学計算など精度が重要でない場合(通常はNUMBERを推奨) |
日付・時刻型
| データ型 | 説明 | 精度 | 使い分け |
|---|---|---|---|
| DATE | 日付+時刻(秒まで) | 秒 | 登録日時・更新日時など一般的な日時 |
| TIMESTAMP(n) | 高精度タイムスタンプ | 最大マイクロ秒(n=0〜9) | ミリ秒・マイクロ秒が必要な場合 |
| TIMESTAMP WITH TIME ZONE | タイムゾーン付きタイムスタンプ | マイクロ秒 | 複数タイムゾーンをまたぐシステム |
| INTERVAL YEAR TO MONTH | 年・月の間隔 | – | 年齢・在籍年数の格納 |
| INTERVAL DAY TO SECOND | 日・時・分・秒の間隔 | マイクロ秒 | 処理時間・経過時間の格納 |
MySQLの
DATE 型は日付のみですが、Oracle の DATE 型は時刻(時・分・秒)も格納します。日付だけを扱いたい場合は TRUNC(日付列) で時刻部分を切り捨てて比較することを忘れずに。バイナリ・大容量型
| データ型 | 説明 | 最大サイズ | 使い分け |
|---|---|---|---|
| BLOB | バイナリラージオブジェクト | 最大128TB | 画像・PDF・動画ファイルのバイナリ格納 |
| RAW(n) | 固定長バイナリ | 2000バイト | 小容量のバイナリデータ(UUIDなど) |
| LONG RAW | 可変長バイナリ(非推奨) | 2GB | 新規設計では BLOB を使うこと |
制約の種類と書き方
制約には列定義の直後に書く「インライン制約(列レベル制約)」と、すべての列定義の後に書く「テーブルレベル制約」の2種類の書き方があります。
| 制約の種類 | インライン記述 | テーブルレベル記述 | 複合列対応 |
|---|---|---|---|
| PRIMARY KEY | ◯ | ◯ | ◯(テーブルレベルのみ) |
| FOREIGN KEY | ◯ | ◯ | ◯(テーブルレベルのみ) |
| UNIQUE | ◯ | ◯ | ◯(テーブルレベルのみ) |
| NOT NULL | ◯ | ✕(列レベルのみ) | ✕ |
| CHECK | ◯ | ◯ | △(単一列のみ推奨) |
NOT NULL は必ず列定義のインラインに書く必要があります。テーブルレベル制約(列定義の後ろ)に CONSTRAINT c1 NOT NULL (col1) のように書くとエラーになります。これは Oracle 固有の挙動で、他のDBから移行する際に見落としやすいポイントです。制約名を省略すると Oracle が
SYS_C0012345 のような名前を自動生成します。エラーメッセージに制約名が出るため、名前がないと原因が一瞬でわかりません。ALTER TABLE … DROP CONSTRAINT や DISABLE CONSTRAINT のときにも困るため、必ず CONSTRAINT 制約名 で命名することを強く推奨します。命名規則例: 主キー →
pk_テーブル名、外部キー → fk_テーブル名_参照先、チェック → ck_テーブル名_列名PRIMARY KEY(主キー制約)
テーブルの各行を一意に識別する列に設定します。自動的に NOT NULL と UNIQUE が付きます。
CREATE TABLE emp (
emp_id NUMBER(10) CONSTRAINT pk_emp PRIMARY KEY,
emp_name VARCHAR2(100) NOT NULL
);
CREATE TABLE order_detail (
order_id NUMBER(10) NOT NULL,
line_no NUMBER(5) NOT NULL,
product_id NUMBER(10) NOT NULL,
qty NUMBER(10) NOT NULL,
CONSTRAINT pk_order_detail PRIMARY KEY (order_id, line_no)
);
FOREIGN KEY(外部キー制約)
他テーブルの列を参照する関係を定義します。参照先のテーブルに存在しない値の登録を防ぎます。
-- 部署マスター(参照される側)
CREATE TABLE dept (
dept_id NUMBER(5) NOT NULL,
dept_name VARCHAR2(100) NOT NULL,
CONSTRAINT pk_dept PRIMARY KEY (dept_id)
);
-- 社員テーブル(参照する側)
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
emp_name VARCHAR2(100) NOT NULL,
dept_id NUMBER(5),
CONSTRAINT pk_emp PRIMARY KEY (emp_id),
CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES dept (dept_id)
);
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
dept_id NUMBER(5),
CONSTRAINT pk_emp PRIMARY KEY (emp_id),
CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id)
REFERENCES dept (dept_id)
ON DELETE CASCADE
);
参照先の列に PRIMARY KEY または UNIQUE 制約がないと
ORA-02270: この列リストには、一致する一意キーまたは主キーがありません エラーになります。また、外部キー列にはインデックスを作成することを推奨します。親テーブルの行を削除する際にフルスキャンが発生しパフォーマンスが低下するためです。
UNIQUE(一意制約)
列の値が重複しないことを保証します。NULL は重複チェックの対象外です(複数行に NULL が入っても制約違反にならない)。
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
emp_email VARCHAR2(200) NOT NULL,
CONSTRAINT pk_emp PRIMARY KEY (emp_id),
CONSTRAINT uq_emp_email UNIQUE (emp_email)
);
NOT NULL(非NULL制約)
列に NULL 値を許可しません。列定義のインラインに書くのが一般的です。
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
emp_name VARCHAR2(100) NOT NULL, -- 必須項目
memo VARCHAR2(500) -- NULL許可(省略可能な列)
);
CHECK(チェック制約)
列の値が満たすべき条件を定義します。条件式を満たさない INSERT / UPDATE はエラーになります。
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
salary NUMBER(10, 2) NOT NULL,
gender CHAR(1),
CONSTRAINT pk_emp PRIMARY KEY (emp_id),
CONSTRAINT ck_emp_salary CHECK (salary >= 0),
CONSTRAINT ck_emp_gender CHECK (gender IN ('M', 'F', 'X'))
);
DEFAULT(デフォルト値)
INSERT 時に値を省略した列に自動的に入る値を定義します。制約ではなく列定義のオプションです。
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
status VARCHAR2(10) DEFAULT 'ACTIVE' NOT NULL,
created_at DATE DEFAULT SYSDATE NOT NULL,
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,
is_deleted NUMBER(1) DEFAULT 0 NOT NULL,
CONSTRAINT pk_emp PRIMARY KEY (emp_id)
);
実践的なテーブル作成例
マスターテーブル(部署マスター)
CREATE TABLE dept (
dept_id NUMBER(5) NOT NULL,
dept_code VARCHAR2(10) NOT NULL,
dept_name VARCHAR2(100) NOT NULL,
parent_id NUMBER(5),
sort_order NUMBER(3) DEFAULT 0 NOT NULL,
is_active NUMBER(1) DEFAULT 1 NOT NULL,
created_at DATE DEFAULT SYSDATE NOT NULL,
updated_at DATE DEFAULT SYSDATE NOT NULL,
CONSTRAINT pk_dept PRIMARY KEY (dept_id),
CONSTRAINT uq_dept_code UNIQUE (dept_code),
CONSTRAINT fk_dept_parent FOREIGN KEY (parent_id) REFERENCES dept (dept_id),
CONSTRAINT ck_dept_active CHECK (is_active IN (0, 1))
);
トランザクションテーブル(受注明細)
CREATE TABLE order_detail (
order_id NUMBER(10) NOT NULL,
line_no NUMBER(5) NOT NULL,
product_id NUMBER(10) NOT NULL,
qty NUMBER(10) NOT NULL,
unit_price NUMBER(12, 2) NOT NULL,
tax_rate NUMBER(5, 2) DEFAULT 0.10 NOT NULL,
created_at DATE DEFAULT SYSDATE NOT NULL,
CONSTRAINT pk_order_detail PRIMARY KEY (order_id, line_no),
CONSTRAINT fk_od_product FOREIGN KEY (product_id)
REFERENCES product (product_id),
CONSTRAINT ck_od_qty CHECK (qty > 0),
CONSTRAINT ck_od_unit_price CHECK (unit_price >= 0),
CONSTRAINT ck_od_tax_rate CHECK (tax_rate BETWEEN 0 AND 1)
);
CTAS(CREATE TABLE AS SELECT):既存テーブルからコピーする
CREATE TABLE AS SELECT(CTAS)を使うと、既存テーブルのデータ構造やデータを元に新しいテーブルを作成できます。テーブルのコピー・バックアップ・集計テーブルの作成などに頻繁に使われます。
-- emp テーブルのデータを emp_bak にコピー CREATE TABLE emp_bak AS SELECT * FROM emp;
-- WHERE 1=2 で必ず0件になる条件を使い、構造のみコピー CREATE TABLE emp_work AS SELECT * FROM emp WHERE 1 = 2;
-- 特定列・特定部署のみコピー CREATE TABLE emp_dept10 AS SELECT emp_id, emp_name, salary FROM emp WHERE dept_id = 10;
-- 部署別集計テーブルを作成
CREATE TABLE dept_summary AS
SELECT
dept_id,
COUNT(*) AS emp_count,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary
FROM emp
GROUP BY dept_id;
CTAS で作成したテーブルには元のテーブルの制約(PRIMARY KEY / FOREIGN KEY / CHECK など)はコピーされません。NOT NULL 制約は列定義としてコピーされる場合がありますが、名前付き制約は引き継がれないため、CTAS 後に必要な制約を
ALTER TABLE で追加してください。インデックスもコピーされないので注意が必要です。表領域(TABLESPACE)を指定してテーブルを作成する
Oracle では、テーブルをどの表領域に格納するか指定できます。省略するとユーザーのデフォルト表領域に作成されます。大規模システムでは I/O 分散や管理のために表領域を分けることが一般的です。
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
emp_name VARCHAR2(100) NOT NULL,
CONSTRAINT pk_emp PRIMARY KEY (emp_id)
)
TABLESPACE users;
CREATE TABLE emp (
emp_id NUMBER(10) NOT NULL,
emp_name VARCHAR2(100) NOT NULL,
CONSTRAINT pk_emp PRIMARY KEY (emp_id)
USING INDEX TABLESPACE indx -- インデックスは indx 表領域
)
TABLESPACE data; -- テーブル本体は data 表領域
テーブル作成後の確認方法
SELECT table_name, tablespace_name, num_rows, status FROM USER_TABLES WHERE TABLE_NAME = 'EMP';
SELECT
column_id,
column_name,
data_type,
data_length,
data_precision,
data_scale,
nullable,
data_default
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'EMP'
ORDER BY column_id;
SELECT
constraint_name,
constraint_type,
search_condition,
r_constraint_name,
status
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'EMP'
ORDER BY constraint_type, constraint_name;
CREATE TABLE に必要な権限
| 作業 | 必要な権限 |
|---|---|
| 自スキーマにテーブルを作成する | CREATE TABLE システム権限 |
| 他スキーマにテーブルを作成する | CREATE ANY TABLE システム権限(DBA権限) |
| 指定した表領域を使う | その表領域に対する QUOTA または UNLIMITED TABLESPACE |
-- CREATE TABLE 権限を付与 GRANT CREATE TABLE TO scott; -- 表領域の使用枠を付与(10MB) ALTER USER scott QUOTA 10M ON users; -- 表領域の使用を無制限に許可 GRANT UNLIMITED TABLESPACE TO scott;
テーブル作成後の関連操作
- カラム追加・変更・削除:【Oracle】ALTER TABLE文でテーブルの変更を行う方法
- インデックスの作成:【Oracle】インデックスの作成、再構築、削除
- グローバル一時テーブルの作成:【Oracle】グローバル一時テーブル(GTT)の作成と使い方完全解説
- シーケンスで主キーを自動採番する:【Oracle】シーケンスを作成する方法完全ガイド
よくある質問
CREATE TABLE システム権限が付与されていません。DBA 権限を持つユーザーに GRANT CREATE TABLE TO ユーザー名; で付与してもらってください。表領域のクォータ不足(ORA-01536)の場合は ALTER USER ユーザー名 QUOTA UNLIMITED ON 表領域名; も必要です。DROP TABLE テーブル名; で削除できます。デフォルトではゴミ箱(Recycle Bin)に移動するため、FLASHBACK TABLE テーブル名 TO BEFORE DROP; で復元できます。完全に削除する場合は DROP TABLE テーブル名 PURGE; を使います。VARCHAR2(n) はバイト単位または文字単位でサイズを指定し、データベースのキャラクタセットを使います。NVARCHAR2(n) は National Character Set(通常 UTF-16 または UTF-8)を使い、多言語データを格納します。日本語のみを扱う場合は VARCHAR2 でデータベースの文字コードが UTF-8 または JA16SJIS であれば問題ありません。ALTER TABLE テーブル名 ADD CONSTRAINT pk_xxx PRIMARY KEY (列名); で制約を追加してください。CREATE OR REPLACE TABLE 構文はありません。先に DROP TABLE テーブル名 PURGE; で削除してから CREATE TABLE を実行するか、TRUNCATE TABLE テーブル名; でデータだけ削除する方法があります。まとめ
Oracle での CREATE TABLE のポイントをまとめます。
| 内容 | ポイント |
|---|---|
| 文字型 | VARCHAR2 を使う(VARCHAR は非推奨) |
| 数値型 | NUMBER(p, s) で精度とスケールを明示する |
| 日付型 | DATE は時刻情報を持つ(秒まで)。ミリ秒以下は TIMESTAMP を使う |
| 主キー | 単一列は CONSTRAINT 名 PRIMARY KEY でインラインに書ける。複合キーはテーブルレベルで定義 |
| 外部キー | 参照先には PRIMARY KEY or UNIQUE が必要。外部キー列にインデックスを作ること |
| 制約名 | 必ず命名規則に従って付ける(自動生成名は管理が困難) |
| CTAS(CREATE TABLE AS SELECT) | テーブルのコピー・バックアップ・集計テーブル作成に便利。ただし制約・インデックスはコピーされないため ALTER TABLE で追加が必要 |
| 表領域 | 大規模システムはテーブルとインデックスを別表領域に分けることを検討 |