【Oracle】テーブルを作成する方法完全ガイド|CREATE TABLE・全データ型・制約・CTAS・表領域指定まで解説

Oracleでテーブルを作成するには CREATE TABLE 文を使います。MySQLや PostgreSQL と基本的な考え方は同じですが、Oracle 独自のデータ型(VARCHAR2NUMBER)や制約の書き方、表領域(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 表領域名];

最もシンプルな例として、社員テーブルを作成してみます。

SQL(シンプルなテーブル作成例)
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データ
VARCHAR は使わない
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 日・時・分・秒の間隔 マイクロ秒 処理時間・経過時間の格納
Oracle の DATE は時刻情報を持つ
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 はテーブルレベルでは書けない
NOT NULL は必ず列定義のインラインに書く必要があります。テーブルレベル制約(列定義の後ろ)に CONSTRAINT c1 NOT NULL (col1) のように書くとエラーになります。これは Oracle 固有の挙動で、他のDBから移行する際に見落としやすいポイントです。
制約名は必ず付けること
制約名を省略すると Oracle が SYS_C0012345 のような名前を自動生成します。エラーメッセージに制約名が出るため、名前がないと原因が一瞬でわかりません。ALTER TABLE … DROP CONSTRAINTDISABLE CONSTRAINT のときにも困るため、必ず CONSTRAINT 制約名 で命名することを強く推奨します。
命名規則例: 主キー → pk_テーブル名、外部キー → fk_テーブル名_参照先、チェック → ck_テーブル名_列名

PRIMARY KEY(主キー制約)

テーブルの各行を一意に識別する列に設定します。自動的に NOT NULLUNIQUE が付きます。

SQL(インライン記述)
CREATE TABLE emp (
    emp_id    NUMBER(10)    CONSTRAINT pk_emp PRIMARY KEY,
    emp_name  VARCHAR2(100) NOT NULL
);
SQL(テーブルレベル記述・複合主キーにも対応)
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(外部キー制約)

他テーブルの列を参照する関係を定義します。参照先のテーブルに存在しない値の登録を防ぎます。

SQL(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)
);
SQL(ON DELETE CASCADE:親行削除時に子行も削除)
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
);
FOREIGN KEY の参照先は PRIMARY KEY または UNIQUE 制約が必要
参照先の列に PRIMARY KEY または UNIQUE 制約がないと ORA-02270: この列リストには、一致する一意キーまたは主キーがありません エラーになります。
また、外部キー列にはインデックスを作成することを推奨します。親テーブルの行を削除する際にフルスキャンが発生しパフォーマンスが低下するためです。

UNIQUE(一意制約)

列の値が重複しないことを保証します。NULL は重複チェックの対象外です(複数行に NULL が入っても制約違反にならない)。

SQL(UNIQUE 制約)
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 値を許可しません。列定義のインラインに書くのが一般的です。

SQL(NOT NULL)
CREATE TABLE emp (
    emp_id   NUMBER(10)    NOT NULL,
    emp_name VARCHAR2(100) NOT NULL,   -- 必須項目
    memo     VARCHAR2(500)             -- NULL許可(省略可能な列)
);

CHECK(チェック制約)

列の値が満たすべき条件を定義します。条件式を満たさない INSERT / UPDATE はエラーになります。

SQL(CHECK 制約)
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 時に値を省略した列に自動的に入る値を定義します。制約ではなく列定義のオプションです。

SQL(DEFAULT 値)
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)
);

実践的なテーブル作成例

マスターテーブル(部署マスター)

SQL(部署マスター)
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))
);

トランザクションテーブル(受注明細)

SQL(受注明細テーブル)
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)を使うと、既存テーブルのデータ構造やデータを元に新しいテーブルを作成できます。テーブルのコピー・バックアップ・集計テーブルの作成などに頻繁に使われます。

SQL(テーブルをそのままコピー)
-- emp テーブルのデータを emp_bak にコピー
CREATE TABLE emp_bak AS
SELECT * FROM emp;
SQL(構造だけコピー・データなし)
-- WHERE 1=2 で必ず0件になる条件を使い、構造のみコピー
CREATE TABLE emp_work AS
SELECT * FROM emp WHERE 1 = 2;
SQL(特定の列・条件でコピー)
-- 特定列・特定部署のみコピー
CREATE TABLE emp_dept10 AS
SELECT emp_id, emp_name, salary
FROM emp
WHERE dept_id = 10;
SQL(集計テーブルを作成)
-- 部署別集計テーブルを作成
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 で制約はコピーされない
CTAS で作成したテーブルには元のテーブルの制約(PRIMARY KEY / FOREIGN KEY / CHECK など)はコピーされません。NOT NULL 制約は列定義としてコピーされる場合がありますが、名前付き制約は引き継がれないため、CTAS 後に必要な制約を ALTER TABLE で追加してください。インデックスもコピーされないので注意が必要です。

表領域(TABLESPACE)を指定してテーブルを作成する

Oracle では、テーブルをどの表領域に格納するか指定できます。省略するとユーザーのデフォルト表領域に作成されます。大規模システムでは I/O 分散や管理のために表領域を分けることが一般的です。

SQL(TABLESPACE 指定)
CREATE TABLE emp (
    emp_id   NUMBER(10)    NOT NULL,
    emp_name VARCHAR2(100) NOT NULL,
    CONSTRAINT pk_emp PRIMARY KEY (emp_id)
)
TABLESPACE users;
SQL(テーブルとインデックスを別表領域に分ける)
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 表領域
表領域の確認・作成方法は【Oracle】表領域の作成・削除・変更・確認方法を参照してください。

テーブル作成後の確認方法

SQL(テーブルの存在確認)
SELECT table_name, tablespace_name, num_rows, status
FROM USER_TABLES
WHERE TABLE_NAME = 'EMP';
SQL(列定義の確認)
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;
SQL(制約の確認)
SELECT
    constraint_name,
    constraint_type,
    search_condition,
    r_constraint_name,
    status
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'EMP'
ORDER BY constraint_type, constraint_name;
テーブル作成後にカラム追加や制約変更が必要になった場合は【Oracle】ALTER TABLE文でテーブルの変更を行う方法を参照してください。

CREATE TABLE に必要な権限

作業 必要な権限
自スキーマにテーブルを作成する CREATE TABLE システム権限
他スキーマにテーブルを作成する CREATE ANY TABLE システム権限(DBA権限)
指定した表領域を使う その表領域に対する QUOTA または UNLIMITED TABLESPACE
SQL(権限付与:DBA が実行)
-- CREATE TABLE 権限を付与
GRANT CREATE TABLE TO scott;

-- 表領域の使用枠を付与(10MB)
ALTER USER scott QUOTA 10M ON users;

-- 表領域の使用を無制限に許可
GRANT UNLIMITED TABLESPACE TO scott;
権限の確認・付与方法の詳細は【Oracle】ユーザ権限を確認する方法完全ガイドを参照してください。

テーブル作成後の関連操作

よくある質問

ORA-01031: 権限が不足しています エラーが出て CREATE TABLE できません
CREATE TABLE システム権限が付与されていません。DBA 権限を持つユーザーに GRANT CREATE TABLE TO ユーザー名; で付与してもらってください。表領域のクォータ不足(ORA-01536)の場合は ALTER USER ユーザー名 QUOTA UNLIMITED ON 表領域名; も必要です。
ORA-02270: この列リストには、一致する一意キーまたは主キーがありません
外部キー(FOREIGN KEY)の参照先列に PRIMARY KEY または UNIQUE 制約がありません。参照先テーブルの該当列に PRIMARY KEY または UNIQUE 制約を先に作成してから外部キーを定義してください。
テーブルを誤って作成した場合に削除するには
DROP TABLE テーブル名; で削除できます。デフォルトではゴミ箱(Recycle Bin)に移動するため、FLASHBACK TABLE テーブル名 TO BEFORE DROP; で復元できます。完全に削除する場合は DROP TABLE テーブル名 PURGE; を使います。
VARCHAR2 と NVARCHAR2 の違いは何ですか?
VARCHAR2(n) はバイト単位または文字単位でサイズを指定し、データベースのキャラクタセットを使います。NVARCHAR2(n) は National Character Set(通常 UTF-16 または UTF-8)を使い、多言語データを格納します。日本語のみを扱う場合は VARCHAR2 でデータベースの文字コードが UTF-8 または JA16SJIS であれば問題ありません。
CTAS(CREATE TABLE AS SELECT)で作ったテーブルに PRIMARY KEY がありません
CTAS では元のテーブルの制約はコピーされません。CTAS 後に ALTER TABLE テーブル名 ADD CONSTRAINT pk_xxx PRIMARY KEY (列名); で制約を追加してください。
同じ構造のテーブルが既に存在する場合に再作成したい
Oracle には CREATE OR REPLACE TABLE 構文はありません。先に DROP TABLE テーブル名 PURGE; で削除してから CREATE TABLE を実行するか、TRUNCATE TABLE テーブル名; でデータだけ削除する方法があります。
テーブルの列数・行数に上限はありますか?
1テーブルあたりの列数の上限は 1000 列です(ただし LONG / LOB 型の制限あり)。行数の理論上の上限はテーブルが使える表領域サイズに依存し、実質的に上限はありません。通常の業務システムでは列数・行数で困ることはほぼありません。

まとめ

Oracle での CREATE TABLE のポイントをまとめます。

内容 ポイント
文字型 VARCHAR2 を使う(VARCHAR は非推奨)
数値型 NUMBER(p, s) で精度とスケールを明示する
日付型 DATE は時刻情報を持つ(秒まで)。ミリ秒以下は TIMESTAMP を使う
主キー 単一列は CONSTRAINT 名 PRIMARY KEY でインラインに書ける。複合キーはテーブルレベルで定義
外部キー 参照先には PRIMARY KEY or UNIQUE が必要。外部キー列にインデックスを作ること
制約名 必ず命名規則に従って付ける(自動生成名は管理が困難)
CTAS(CREATE TABLE AS SELECT) テーブルのコピー・バックアップ・集計テーブル作成に便利。ただし制約・インデックスはコピーされないため ALTER TABLE で追加が必要
表領域 大規模システムはテーブルとインデックスを別表領域に分けることを検討