◀ 2.

Oracle 19cの列追加|ADD・DEFAULTと既存行・NOT NULLの条件

▶

対象: Oracle Database 19cの通常表への列追加。IDENTITY・仮想列を除く通常列を中心に説明します。以下の他製品例は比較用で、Oracleへそのまま実行する手順ではありません。新列の初期値、将来INSERTの省略値、既存列に残るNULLを分けて判断します。通常表という指定だけでは列種別を限定できません。IDENTITY追加は既存行をsequence generatorで採番し、暗黙のNOT NULLを伴う別仕様です(既存行への採番順は非決定的)。仮想列も式から値を導く別仕様で、通常列のDEFAULTなしNOT NULL追加の拒否条件を一律に転用しません。

新列追加時の既存行と既存列DEFAULT変更の違い
新列のDEFAULTと既存列のNULLは別。図は概念説明で、無待機や移行成功を実証していません。
この記事の要点
  • 既存テーブルにカラムを追加するには ALTER TABLE テーブル名 ADD カラム名 データ型 を使う
  • Oracle / SQL Server は ADD、PostgreSQL / MySQL は ADD COLUMN(COLUMN は省略可能)
  • Oracle 19cではこのVARCHARのような通常列について、既存行がある表へのDEFAULTなしNOT NULL列追加は不可。IDENTITY・仮想列は別仕様。新列の初期値と既存列のDEFAULT変更は別
  • 大規模テーブルに ALTER TABLE をかけるとロックや書き込み停止が発生する DB があるので注意
  • この比較ではMySQLのFIRST / AFTERとOracleのADDを分ける。位置変更だけでも既存SQL・アプリ互換を確認

ALTER TABLE ADD とは

既存のテーブルに新しいカラム(列)を追加する SQL 文です。テーブルを再作成しなくてもスキーマを拡張できるため、運用中のデータベースで頻繁に使われます。

基本構文

Oracle 19cのADDとPostgreSQL/MySQLのADD COLUMNを区別する構文教材です。表名・列名・角括弧は置換用の記号で、一括実行できません。DDLは定義を変更します。実Oracleを含め以下のSQLは未実行です。

-- 標準構文
ALTER TABLE テーブル名
  ADD カラム名 データ型 [制約];

-- PostgreSQL / MySQL は COLUMN キーワード可(省略可)
ALTER TABLE テーブル名
  ADD COLUMN カラム名 データ型 [制約];

もっともシンプルな例

Oracle 19cの旧例を保持しています。このVARCHARのような通常列は、test_tableに既存行があればDEFAULTなしNOT NULL追加を拒否されます。IDENTITY・仮想列とは別仕様です。VARCHARは現行OracleでVARCHAR2と同義ですがOracleはVARCHAR2を推奨し、長さはBYTE/CHAR条件も確認します。値埋めや制約解除による強行手順ではありません。実Oracle未実行です。

ALTER TABLE test_table
  ADD new_col VARCHAR(20) NOT NULL;

Oracle 19cではこのVARCHARのような通常列は、既存行が1行でもある表にDEFAULTなしのNOT NULL列を追加できません。IDENTITY・仮想列へこの拒否条件を一律に広げません。空表でも以後のwriterが値を供給する設計が必要です。エラーを避けるだけの一律値設定はしません。

DEFAULT 値付きで追加(推奨)

旧見出しの「推奨」は全行へ任意の既定値を配る推奨ではありません。業務上正しい初期値を定義できる場合だけ検討し、NULL・未設定・実際の作成時刻を捏造しません。通常DEFAULTと明示NULLへ適用するDEFAULT ON NULLは別指定です。

Oracle 19cのDEFAULT付き追加として独立に読む旧3例です。active/0は業務上正しい値の保証ではなく、CURRENT_TIMESTAMPを実際の作成履歴時刻とみなせません。表/列/型の前提を確認してください。既存列のDEFAULT変更とは異なり、新列の既存行には追加時DEFAULTが適用されます。通常DEFAULTは後続INSERTの値省略時等に働き、明示NULLの置換にはなりません。実Oracle未実行です。

ALTER TABLE test_table
  ADD status VARCHAR(20) DEFAULT 'active' NOT NULL;

-- 数値型
ALTER TABLE orders
  ADD discount NUMERIC(5,2) DEFAULT 0 NOT NULL;

-- 日付型(追加時の現在時刻で埋める)
ALTER TABLE users
  ADD created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;

複数カラムを一度に追加

DB によって書き方が異なります。

Oracle 19c / MySQL 8.4の括弧ADD、PostgreSQL / SQL Serverの複数追加を比較する独立例です。MySQLの括弧ADD自体は有効ですが、型・既存行・重複列・DEFAULTの条件は別です。先の例の続きとして実行しないでください。各実DB未実行です。

-- Oracle / MySQL(括弧でまとめる)
ALTER TABLE test_table
  ADD (
    col1 VARCHAR(20),
    col2 INT DEFAULT 0
  );

-- PostgreSQL(カンマで連続)
ALTER TABLE test_table
  ADD COLUMN col1 VARCHAR(20),
  ADD COLUMN col2 INT DEFAULT 0;

-- SQL Server
ALTER TABLE test_table
  ADD col1 VARCHAR(20),
      col2 INT DEFAULT 0;

各 DB のクセ早見表

DBキーワード位置指定備考
OracleADD(複数は括弧)不可ADDによる列位置の指定は不可。DEFAULT付き追加には条件付きmetadata最適化があるが、無待機の保証ではない
MySQLADD [COLUMN]FIRST / AFTER 可MySQL 8.4のFIRST / AFTER。対応algorithmと対象制限・metadata lockを別途確認
PostgreSQLADD COLUMN(複数 OK)不可PostgreSQL 11以降の定数DEFAULTは各行の即時更新を省ける。volatile式は既存行ごとの評価が必要
SQL ServerADD(カンマで複数)不可NOT NULL は DEFAULT 必須または既存行ゼロ
SQLiteADD COLUMN不可制約に制限あり(PRIMARY KEY 不可など)

MySQL の位置指定

MySQLのFIRST / AFTER用の旧2例で、Oracle 19cの列位置変更構文ではありません。usersとidの存在だけでなく既存SQL/アプリ互換・algorithm・ロックを確認します。実DB未実行です。

-- 既存の id カラムの直後に追加
ALTER TABLE users
  ADD COLUMN nickname VARCHAR(50) AFTER id;

-- 先頭に追加
ALTER TABLE users
  ADD COLUMN serial_no INT FIRST;

計算列(生成列)を追加する

他のカラムの値から自動計算される列も追加できます。

PostgreSQL / MySQL / SQL Serverの生成列比較例を保持しています。OracleのADDへ転用せず、表とpriceの型、式の評価・制限、製品版を確認します。同じ列を3回追加する連続手順ではありません。実DB未実行です。

-- PostgreSQL
ALTER TABLE orders
  ADD COLUMN total_with_tax NUMERIC(10,2)
  GENERATED ALWAYS AS (price * 1.1) STORED;

-- MySQL 5.7+
ALTER TABLE orders
  ADD COLUMN total_with_tax NUMERIC(10,2)
  AS (price * 1.1) VIRTUAL;

-- SQL Server
ALTER TABLE orders
  ADD total_with_tax AS (price * 1.10) PERSISTED;

大規模テーブルでの注意

  • テーブル全体のロックが発生する DB がある(MySQL の InnoDB は条件次第でオンライン DDL 可)
  • Oracle 19cのDEFAULT付きADDは条件を満たせば値をmetadataに保持し、読取結果へ反映する。常に全行更新でも、常に瞬時でもない
  • Oracleの最適化には表種別・列型・VPD・DEFAULT式等の制限がある。索引構成表・一時表・cluster表・queue表・object表・materialized viewのcontainer表、追加LOB/object/nested table/暗号化列、sequenceのCURRVAL/NEXTVAL等は条件を確認。非対応では各行を更新し得る。VPDの例外権限を最適化のために追加する案内ではない
  • メンテナンス枠でもロック待ち・実行時間・復旧を検証する。時間帯だけでは安全にならない
  • pt-online-schema-change / gh-ostはMySQL向けの比較で、OracleのADD用ではない。外部キー・trigger・切替・負荷とツールの版制限を確認し、無停止とは保証しない

追加後の確認

製品別の一覧取得例です。DESCはOracle SQL*Plus等のクライアント命令、バックスラッシュdはpsql命令でSQLではありません。USER_TAB_COLUMNSは自schemaの定義確認で、NULL件数・全依存・利用頻度や別schema不存在の証明ではありません。接続先/実名と長さ・精度・DEFAULT等も別途照合します。実Oracleを含め未実行です。

-- カラム一覧
-- Oracle
DESC test_table;
SELECT column_name, data_type, nullable
  FROM user_tab_columns WHERE table_name = 'TEST_TABLE';

-- PostgreSQL
\d test_table

-- MySQL
SHOW COLUMNS FROM test_table;
DESCRIBE test_table;

-- SQL Server
EXEC sp_columns 'test_table';

NULL 許可 / NOT NULL の選び方

新規カラムの NULL 許可は後から変えるのが面倒なため、追加時に慎重に決めます。判断基準は次のとおりです。

  • 業務上「未設定」が意味を持つ → NULL 許可
  • 論理的に必ず値があるべき場合も、既存行に正しい値を決定できるかが先。DEFAULTを設定するだけで既存列のNULLが埋まるわけではない
  • 段階的移行は候補の一つ。全writerの対応・既存値の意味・再流入・制約検証を確認し、NULL許可で追加した事実を安全の証明にしない

段階的マイグレーションの定番手順

以下は段階を分けて評価するための確認順序です。無停止・短時間・全体ROLLBACKを保証する実行手順ではありません。既存行の意味を確認しないactive等への一律backfillは行いません。

  1. NULL許可での追加を検討し、対象・DDLのロックと待機・取消境界を確認
  2. 旧版アプリ・バッチ・複数writerを含め新列への値供給と読取互換を確認
  3. 業務上正しい値を承認してから必要範囲だけbackfill。分割単位・再開・負荷・NULL再流入を評価
  4. 残存NULLと全writerの再流入を確認した上で制約検証とNOT NULL化を別途計画。観測時の0件だけを将来の保証にしない
  5. 追加とは別に保持すべき旧値・依存・復旧を確認。旧列DROPを定番の最終段階にしない

PostgreSQL/MySQLの旧移行例でOracle用の連続手順ではありません。WHERE status IS NULLでも全NULL行をactiveに変える業務判断は未確認です。このUPDATEを推奨せず、旧/複数writerのNULL再流入、分割・再開・検証を先に設計します。MySQL MODIFYは残す全属性の再記述が必要で、先行UPDATEとDDLを一括ROLLBACKできると考えないでください。実DB未実行です。

-- 1. 追加
ALTER TABLE users ADD COLUMN status VARCHAR(20);

-- 2. (アプリデプロイ後)3. 既存行を埋める
UPDATE users SET status = 'active' WHERE status IS NULL;

-- 4. NOT NULL 化
ALTER TABLE users ALTER COLUMN status SET NOT NULL;  -- PostgreSQL
ALTER TABLE users MODIFY status VARCHAR(20) NOT NULL; -- MySQL

関連

  • ALTER TABLE — テーブル変更全般
  • カラムの削除(DROP COLUMN)
  • カラムのデータ型変更(MODIFY / ALTER COLUMN)
  • カラム名変更(RENAME COLUMN)
  • CREATE TABLE — テーブル新規作成

Oracle 19cの確定境界と実行前の確認

通常表のDDLは構文上有効なDDLの実行前と成功後に暗黙COMMITがあります。DDLが失敗しても先行DMLが確定するため、後からROLLBACKすればUPDATEまで戻るとは保証しません。ALTER TABLEを通常の利用者ROLLBACKで取り消すことはできません。実行前に未確定DMLを分離し、接続先・所有schema・実名・現定義・対象行と復旧方法を確認します。

一時表を一括して例外にしません。transaction-specific private temporary tableのON COMMIT DROP DEFINITIONによる作成は既存transactionを暗黙COMMITしませんが、session-specificのPRESERVE DEFINITIONによる作成は暗黙COMMITします。これは作成時の限定条件で、通常表のADD/MODIFYを可逆にする仕組みではありません。

変更前後で型・長さのBYTE/CHAR意味・精度・NULL・DEFAULT・コメント・文字集合/照合順序・索引/制約と既存値を照合します。旧アプリ・バッチ・複数writerのNULL再流入も確認し、既存NULLを一律unknown/activeに置換したり、保護の解除・SQL mode変更・列DROPへ誘導しません。

MySQL向け外部ツールも読取診断とは限りません。pt-online-schema-changeは外部キーに特別な処理と追加リスクがあり、--dry-runでも新表を作成・変更します。gh-ostは外部キー制約とtriggerを非対応としています。制限を避けるために外部キーを外したり検査を無効化する手順ではありません。MySQL online DDLでもmetadata lock待ちと最終段階の排他取得があり、無停止の保証ではありません。

確認資料と検証範囲

2026-10-27に公式一次資料を確認しました。Oracle実機では未実行です。他製品の旧SQL、ロック、並行writer、backfill、性能、復旧、外部ツールも実測していません。保持したSQLは実行済みの手順ではなく、静的な本文・HTML・履歴ガード検査は実DBの成功保証とは別です。

子ページ

子ページはありません

同階層のページ
  1. 表の作成
  2. カラムの追加
  3. カラムの定義変更
  4. カラムの削除
  5. 表の削除
  6. TRUNCATE文

最近更新/作成されたページ