Query Go
テーブルを作成 - CREATE TABLE の使い方・オプション・サンプル

テーブルを作成 - CREATE TABLE

テーブルを定義する基本 DDL。列名・データ型・DEFAULT・NOT NULL・コメントの書き方を整理

概念図

CREATE TABLE diagram

構文

sql
CREATE TABLE table_name ( column_name data_type [制約], ... );

サンプル

users テーブルを PRIMARY KEY、UNIQUE、NOT NULL、DEFAULT を組み合わせて定義する例

sql
CREATE TABLE users (
  id         BIGSERIAL PRIMARY KEY,
  email      VARCHAR(255) NOT NULL UNIQUE,
  name       VARCHAR(100) NOT NULL,
  status     VARCHAR(20)  NOT NULL DEFAULT 'active',
  created_at TIMESTAMPTZ  NOT NULL DEFAULT NOW()
);

CREATE TABLE の基本構造

CREATE TABLE は新しいテーブルをデータベースに作成する DDL です。テーブル名のあとにカッコで囲んだ列定義リストを書き、各列には「列名 データ型 [列制約]」を指定します。

列の順序は物理的なストレージ配置に影響することがある(とくに MySQL の InnoDB や PostgreSQL のアラインメント)ので、サイズの大きい列を前にまとめるとわずかにディスク効率が上がります。

NOT NULL と DEFAULT

列制約でよく使われるのが NOT NULL(NULL を許さない)と DEFAULT(値を省略したときの既定値)です。両方を組み合わせることで「必須だが INSERT 時に省略可能」な列を作れます。

DEFAULT には定数だけでなく関数(NOW()CURRENT_TIMESTAMP、PostgreSQL の gen_random_uuid() など)も指定できます。

sql
CREATE TABLE orders (
  id         BIGSERIAL PRIMARY KEY,
  user_id    BIGINT      NOT NULL,
  amount     NUMERIC(10, 2) NOT NULL DEFAULT 0,
  placed_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

テーブル・列コメント

運用・保守のために、テーブルや列にコメントを付ける文化は大切です。RDBMS により書き方が違います。

  • PostgreSQL / Oracle: COMMENT ON TABLE ... / COMMENT ON COLUMN ... を別文で指定
  • MySQL: 列定義の末尾に COMMENT '...'、テーブル定義の末尾に COMMENT='...'
  • SQLite / SQL Server: ネイティブなコメント機能は限定的(SQL Server は拡張プロパティ)
sql
-- PostgreSQL
COMMENT ON TABLE users IS 'アプリケーション利用者';
COMMENT ON COLUMN users.status IS 'active / suspended / deleted';

-- MySQL
CREATE TABLE users (
  id BIGINT PRIMARY KEY COMMENT '内部ID',
  email VARCHAR(255) NOT NULL COMMENT 'ログイン用メール'
) COMMENT='アプリケーション利用者';

CREATE TABLE IF NOT EXISTS と CREATE TABLE AS

マイグレーションや冪等性を意識するなら CREATE TABLE IF NOT EXISTS を使うと、既にテーブルがある場合にエラーになりません。

CREATE TABLE ... AS SELECT(CTAS)は既存の問い合わせ結果から新しいテーブルを作ります。バックアップや集計結果の実体化に便利ですが、PRIMARY KEY やインデックス・制約はコピーされない点に注意してください。

sql
-- 冪等な作成
CREATE TABLE IF NOT EXISTS audit_log (
  id BIGSERIAL PRIMARY KEY,
  message TEXT NOT NULL
);

-- CTAS(制約はコピーされない)
CREATE TABLE orders_2025_snapshot AS
SELECT * FROM orders WHERE placed_at < DATE '2026-01-01';

落とし穴

  • 予約語をテーブル名・列名にする: userorder などは多くの RDBMS で予約語。引用符が必要になり事故の元
  • VARCHAR(N) の N を適当に決める: 後から拡張するのは可能でも DB 方言で挙動が違う。設計ドキュメント参照
  • タイムゾーンを意識しない: TIMESTAMPTIMESTAMPTZ は別物。グローバルサービスなら TZ 付きが無難
  • 文字コードと照合順序: MySQL では utf8 ではなく utf8mb4 を使う(絵文字対応)

関連トピック