sqlplus

SQL*Plus 総合ガイド — 機能・操作・活用の全容

SQLPlus は Oracle Database に標準付属するコマンドラインインターフェースであり、データベース管理者および開発者にとって最も基本的かつ強力な対話型ツールである。GUIツールが普及した現在でも、スクリプトによる自動化、緊急時のデータベース操作、CI/CDパイプラインでのSQL実行など、SQLPlus が不可欠な場面は多い。本ガイドでは、SQL*Plus の全機能を体系的に解説し、実務で即活用できる知識を提供する。


目次

  1. SQL*Plus の概要と歴史
  2. インストールと接続
  3. 基本操作と起動方法
  4. SQL*Plus コマンド体系
  5. 書式設定と表示制御
  6. COLUMN コマンドと出力フォーマット
  7. スプールとレポート作成
  8. 変数と代入変数
  9. スクリプティングと自動化
  10. PL/SQL との連携
  11. データのインポート/エクスポート
  12. 管理操作
  13. パフォーマンス分析
  14. セキュリティと認証
  15. SQL*Plus のカスタマイズ
  16. エラーハンドリング
  17. マルチテナント環境での SQL*Plus
  18. SQL*Plus vs 代替ツール
  19. 高度なスクリプティングパターン
  20. クラウド環境での利用
  21. トラブルシューティング
  22. 運用ベストプラクティスとまとめ

1. SQL*Plus の概要と歴史

1.1 SQL*Plus とは

SQLPlus は、Oracle Corporation が提供する Oracle Database 向けのコマンドラインユーティリティである。ユーザーは SQLPlus を通じて、SQL文の実行、PL/SQLブロックの実行、データベースオブジェクトの管理、レポートの生成、スクリプトの実行など、Oracle Database に対するあらゆる操作を対話的またはバッチ的に行うことができる。

SQL*Plus の最大の特徴は、Oracle Database のインストール時に標準で付属する点にある。追加のライセンスやインストールは不要であり、データベースが存在する環境であればどこでも利用可能である。また、GUIを必要としないため、SSHによるリモート接続やスクリプトによる自動化に適している。

1.2 SQL*Plus の主な機能

SQL*Plus は単なるSQL実行ツールではなく、以下の多彩な機能を備えている。

  • 対話型SQL実行: SQL文やPL/SQLブロックをリアルタイムに入力・実行し、結果を即座に確認できる
  • スクリプト実行: あらかじめ作成したSQLスクリプトファイルをバッチモードで実行できる
  • レポート生成: COLUMN、BREAK、COMPUTE、TTITLE、BTITLE などのコマンドを用いて、書式化されたレポートを作成できる
  • データベース管理: STARTUP、SHUTDOWN、ALTER SYSTEM などの管理コマンドを実行できる
  • 変数管理: 代入変数(置換変数)やバインド変数を使用して、動的なSQL実行が可能である
  • 出力制御: スプール機能により、実行結果をファイルに出力できる
  • エラー制御: WHENEVER SQLERROR/OSERROR により、エラー発生時の動作を制御できる

1.3 SQL*Plus の歴史と進化

SQL*Plus の歴史は Oracle Database そのものの歴史と密接に結びついている。

時期バージョン主な変化
1979年Oracle V2UFI (User Friendly Interface) として初めてリリース
1983年Oracle V3SQL*Plus に名称変更、基本コマンド体系の確立
1992年Oracle 7PL/SQL サポートの強化、バインド変数の導入
1997年Oracle 8オブジェクト型のサポート、LOBデータ型への対応
2001年Oracle 9iiSQL*Plus(Webブラウザ版)の導入
2007年Oracle 11giSQL*Plus の廃止、コマンドライン版に統一
2013年Oracle 12cマルチテナント対応、Instant Client 対応の強化
2018年Oracle 18cSQLcl の登場(次世代コマンドラインツール)
2019年Oracle 19c長期サポート版、安定性の向上
2024年Oracle 23aiAI機能統合、JSON Duality View対応

初期の UFI (User Friendly Interface) は非常にシンプルなツールであったが、バージョンを重ねるごとに機能が拡充され、現在では高度なスクリプティングやレポート生成が可能なツールとなっている。

1.4 SQL*Plus のエディション

SQL*Plus には以下のエディションが存在する。

コマンドライン SQL*Plus

最も基本的かつ広く使用されるエディションである。すべてのプラットフォーム(Linux、Windows、macOS)で利用可能であり、本ガイドの主な対象となる。

$ sqlplus scott/tiger@orcl
SQL*Plus: Release 19.0.0.0.0 - Production on Mon Apr 13 10:00:00 2026
Version 19.22.0.0.0
Copyright (c) 1982, 2024, Oracle.  All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.22.0.0.0

SQL>

Windows GUI 版 SQL*Plus (sqlplusw.exe)

Windows 環境でのみ利用可能であった GUI 版の SQL*Plus である。Oracle 11g 以降では非推奨となり、Oracle 12c 以降では配布されていない。現在は SQL Developer が GUI ツールとしての役割を担う。

iSQL*Plus

Oracle 9i で導入された Web ブラウザベースの SQL*Plus である。Webサーバー経由でブラウザからSQL文を実行できたが、Oracle 11g Release 2 で廃止された。現在の後継は Oracle Application Express (APEX) の SQL Workshop である。

Instant Client 版 SQL*Plus

Oracle Instant Client に含まれる軽量版の SQL*Plus である。完全な Oracle Client のインストールを必要とせず、必要最小限のライブラリでリモートの Oracle Database に接続できる。CI/CD 環境やコンテナ環境で広く利用されている。

1.5 SQL*Plus と Oracle Database の関係

SQLPlus は Oracle Database の「フロントエンド」として位置づけられる。内部的には Oracle Call Interface (OCI) を使用してデータベースに接続し、SQL文やPL/SQLブロックをサーバーに送信する。サーバー側で処理された結果は OCI を通じてクライアントに返され、SQLPlus が書式化して画面やファイルに出力する。

┌─────────────┐    OCI/Net    ┌──────────────────┐
│  SQL*Plus    │◄────────────►│  Oracle Database  │
│  (Client)    │   (TCP/IP)   │  (Server)         │
│              │              │                    │
│ ・SQL入力     │              │ ・SQL解析/実行      │
│ ・結果表示    │              │ ・PL/SQL実行       │
│ ・書式制御    │              │ ・トランザクション管理│
│ ・スプール    │              │ ・セキュリティ       │
└─────────────┘              └──────────────────┘

重要な点として、SQL*Plus はデータベースサーバー側では動作せず、常にクライアント側のプロセスとして動作する。ただし、SYSDBA や SYSOPER として接続する場合は、データベースインスタンスが起動していない状態でも接続が可能である(CONNECT / AS SYSDBA)。これは STARTUP コマンドでインスタンスを起動する際に不可欠な機能である。


2. インストールと接続

2.1 インストール方法の選択

SQL*Plus を利用するには、以下のいずれかの方法でインストールを行う。

インストール方法説明用途
Oracle Database フルインストールDB サーバーに付属DB サーバー上での直接操作
Oracle Client フルインストール管理ツール一式を含むDBA ワークステーション
Oracle Instant Client最小限のライブラリ開発環境、CI/CD、コンテナ
RPM パッケージLinux 向けパッケージRed Hat / CentOS / OL 環境

2.2 Oracle Instant Client によるインストール

最も軽量かつ迅速にSQL*Plusを導入できるのが Instant Client 方式である。

Linux (RPM) でのインストール

# Oracle Instant Client の基本パッケージとSQL*Plusをインストール
sudo rpm -ivh oracle-instantclient19.22-basic-19.22.0.0.0-1.x86_64.rpm
sudo rpm -ivh oracle-instantclient19.22-sqlplus-19.22.0.0.0-1.x86_64.rpm

# 共有ライブラリのパスを設定
echo '/usr/lib/oracle/19.22/client64/lib' | sudo tee /etc/ld.so.conf.d/oracle.conf
sudo ldconfig

Linux (ZIP) でのインストール

# ダウンロードしたZIPファイルを展開
mkdir -p /opt/oracle
cd /opt/oracle
unzip instantclient-basic-linux.x64-19.22.0.0.0dbru.zip
unzip instantclient-sqlplus-linux.x64-19.22.0.0.0dbru.zip

# 環境変数の設定
export ORACLE_HOME=/opt/oracle/instantclient_19_22
export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
export PATH=$ORACLE_HOME:$PATH

macOS でのインストール

# Homebrew を使用したインストール(非公式だが便利)
# または Oracle 公式サイトからDMGをダウンロード

# 手動インストール
mkdir -p /opt/oracle
cd /opt/oracle
unzip instantclient-basic-macos.x64-19.22.0.0.0dbru.zip
unzip instantclient-sqlplus-macos.x64-19.22.0.0.0dbru.zip

export ORACLE_HOME=/opt/oracle/instantclient_19_22
export DYLD_LIBRARY_PATH=$ORACLE_HOME:$DYLD_LIBRARY_PATH
export PATH=$ORACLE_HOME:$PATH

Windows でのインストール

REM ZIPファイルを展開後、環境変数を設定
set ORACLE_HOME=C:\oracle\instantclient_19_22
set PATH=%ORACLE_HOME%;%PATH%

2.3 環境変数の設定

SQL*Plus の動作に関わる主要な環境変数を以下に示す。

環境変数説明設定例
ORACLE_HOMEOracle ソフトウェアのルートディレクトリ/u01/app/oracle/product/19.0.0/dbhome_1
ORACLE_SIDローカルインスタンスの識別子ORCL
ORACLE_BASEOracle ディレクトリ構造の基点/u01/app/oracle
PATHSQL*Plus 実行ファイルのパス$ORACLE_HOME/bin:$PATH
LD_LIBRARY_PATH共有ライブラリのパス (Linux)$ORACLE_HOME/lib
TNS_ADMINtnsnames.ora / sqlnet.ora の配置ディレクトリ/opt/oracle/network/admin
TWO_TASKデフォルトの接続先データベース (Linux)ORCL
LOCALデフォルトの接続先データベース (Windows)ORCL
NLS_LANGクライアント側の言語・文字セットJAPANESE_JAPAN.AL32UTF8
SQLPATHSQLスクリプトの検索パス/home/oracle/scripts

~/.bashrc での典型的な設定例

# Oracle 環境変数
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export ORACLE_SID=ORCL
export ORACLE_BASE=/u01/app/oracle
export PATH=$ORACLE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
export TNS_ADMIN=$ORACLE_HOME/network/admin
export NLS_LANG=JAPANESE_JAPAN.AL32UTF8
export SQLPATH=/home/oracle/scripts

2.4 接続方法

ローカル接続(Bequeath接続)

同一ホスト上のデータベースインスタンスに ORACLE_SID を使用して接続する方式である。Oracle Net Listener を経由せず、直接インスタンスに接続する。

# ORACLE_SID が設定されている場合
sqlplus scott/tiger

# ORACLE_SID を明示的に指定
export ORACLE_SID=ORCL
sqlplus / as sysdba

TNS 接続(tnsnames.ora 使用)

tnsnames.ora に定義されたネットサービス名を使用して接続する方式である。リモートデータベースへの接続に使用される。

# tnsnames.ora のエントリを使用
sqlplus scott/tiger@ORCL

# tnsnames.ora の設定例
# $TNS_ADMIN/tnsnames.ora

tnsnames.ora の記述例を以下に示す。

ORCL =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver01.example.com)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl.example.com)
    )
  )

ORCL_HA =
  (DESCRIPTION =
    (FAILOVER = ON)
    (LOAD_BALANCE = ON)
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver01.example.com)(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver02.example.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl_svc.example.com)
    )
  )

EZConnect(簡易接続ネーミング)

tnsnames.ora を使用せず、接続文字列を直接指定する方式である。開発環境やテスト環境で簡易的に使用される。

# 基本形式: user/password@host:port/service_name
sqlplus scott/tiger@dbserver01.example.com:1521/orcl.example.com

# デフォルトポート(1521)使用時はポートを省略可能
sqlplus scott/tiger@dbserver01.example.com/orcl.example.com

# Oracle 19c 以降の拡張 EZConnect (EZConnect Plus)
sqlplus scott/tiger@"tcps://dbserver01.example.com:2484/orcl.example.com?wallet_location=/opt/oracle/wallet&retry_count=3"

LDAP 接続

Oracle Internet Directory (OID) や Active Directory を使用した名前解決による接続方式である。

# sqlnet.ora で LDAP を名前解決方法として設定
# NAMES.DIRECTORY_PATH = (LDAP, TNSNAMES)

sqlplus scott/tiger@ORCL_LDAP

2.5 CONNECT コマンドによる接続変更

SQL*Plus 起動後に別のデータベースやユーザーに切り替える場合は CONNECT コマンドを使用する。

-- 別のユーザーに切り替え
SQL> CONNECT hr/hr_password@ORCL

-- SYSDBA 権限で接続
SQL> CONNECT / AS SYSDBA

-- SYSOPER 権限で接続
SQL> CONNECT sys/password@ORCL AS SYSOPER

-- パスワードを対話的に入力(セキュリティ推奨)
SQL> CONNECT scott@ORCL
Enter password: ********

-- 切断のみ行う
SQL> DISCONNECT

2.6 接続確認

接続後、現在の接続情報を確認する方法を以下に示す。

-- 現在のユーザーを確認
SQL> SHOW USER
USER is "SCOTT"

-- 接続先データベースを確認
SQL> SELECT ora_database_name FROM dual;
SQL> SELECT sys_context('USERENV', 'DB_NAME') FROM dual;
SQL> SELECT sys_context('USERENV', 'SERVICE_NAME') FROM dual;
SQL> SELECT sys_context('USERENV', 'INSTANCE_NAME') FROM dual;

-- データベースバージョンを確認
SQL> SELECT banner FROM v$version;

-- 接続に使用しているプロトコル情報
SQL> SELECT sys_context('USERENV', 'NETWORK_PROTOCOL') FROM dual;

3. 基本操作と起動方法

3.1 SQL*Plus の起動オプション

SQL*Plus の起動にはさまざまなオプションが用意されている。

# 基本的な起動構文
sqlplus [options] [username[/password][@connect_identifier]] [AS {SYSDBA|SYSOPER|SYSASM|SYSDG|SYSKM|SYSRAC|SYSBACKUP}]

主要な起動オプションを以下に示す。

オプション説明使用例
-S / -SILENTサイレントモード(バナー非表示)sqlplus -S scott/tiger@ORCL
-L / -LOGONログイン失敗時に即座に終了sqlplus -L scott/tiger@ORCL
-M / -MARKUPマークアップオプション(HTML出力)sqlplus -M "HTML ON" scott/tiger@ORCL
-R / -RESTRICT制限モード(1,2,3)sqlplus -R 3 scott/tiger@ORCL
-NOLOG接続せずに起動sqlplus /nolog
-F / -FAST高速起動(login.sql をスキップ)sqlplus -F scott/tiger@ORCL
-C / -COMPATIBILITY互換性バージョンの指定sqlplus -C 12.2 scott/tiger@ORCL

サイレントモードの活用

# スクリプトの自動実行(バナー非表示、プロンプト非表示)
sqlplus -S scott/tiger@ORCL <<EOF
SET PAGESIZE 0 FEEDBACK OFF HEADING OFF
SELECT count(*) FROM employees;
EXIT;
EOF

制限モード

制限モードはセキュリティの観点から、SQL*Plus で実行可能なコマンドを制限する機能である。

# レベル1: HOST コマンドと EDIT コマンドを無効化
sqlplus -R 1 scott/tiger@ORCL

# レベル2: レベル1に加え、SPOOL コマンドと SAVE コマンドを無効化
sqlplus -R 2 scott/tiger@ORCL

# レベル3: レベル2に加え、STORE コマンドを無効化(最も制限的)
sqlplus -R 3 scott/tiger@ORCL

3.2 /nolog モードでの起動

データベースに接続せずに SQL*Plus を起動するモードである。主に DBA がインスタンスの起動前に使用する。

# 接続なしで起動
sqlplus /nolog

# 起動後に接続
SQL> CONNECT / AS SYSDBA
Connected to an idle instance.

# インスタンスの起動
SQL> STARTUP
ORACLE instance started.
...
Database opened.

3.3 SYSDBA/SYSOPER としての接続

データベースの起動・停止などの管理操作には SYSDBA または SYSOPER 権限が必要である。

# OS 認証による SYSDBA 接続(パスワード不要)
sqlplus / as sysdba

# パスワードファイル認証による SYSDBA 接続
sqlplus sys/password@ORCL as sysdba

# SYSOPER 接続(起動/停止/バックアップのみ)
sqlplus / as sysoper

# SYSASM 接続(ASM インスタンス管理)
sqlplus / as sysasm

# SYSDG 接続(Data Guard 管理)
sqlplus / as sysdg

# SYSKM 接続(暗号化鍵管理)
sqlplus / as syskm

# SYSBACKUP 接続(バックアップ操作)
sqlplus / as sysbackup

3.4 OS 認証の仕組み

OS 認証を使用する場合、Oracle は現在のOSユーザーが DBA グループ(通常は dba グループ)に属しているかどうかを確認する。

# oracle ユーザーが dba グループに属していることを確認
$ id oracle
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),54322(dba),54323(oper)

# dba グループに属するユーザーは SYSDBA 接続が可能
$ sqlplus / as sysdba
Connected.

3.5 login.sql と glogin.sql

SQL*Plus の起動時に自動的に実行される設定ファイルが2種類存在する。

glogin.sql(グローバルログインスクリプト)

すべてのユーザーに適用される全体設定ファイルである。

配置場所: $ORACLE_HOME/sqlplus/admin/glogin.sql

glogin.sql の設定例を以下に示す。

-- glogin.sql
-- 全ユーザー共通の設定

-- 基本表示設定
SET LINESIZE 200
SET PAGESIZE 50
SET FEEDBACK ON
SET TIMING ON

-- プロンプトにユーザー名とインスタンス名を表示
SET SQLPROMPT "_USER'@'_CONNECT_IDENTIFIER> "

-- NULL値の表示
SET NULL '(null)'

-- サーバー出力を有効化
SET SERVEROUTPUT ON SIZE UNLIMITED

-- 日付書式の設定
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF3';

-- エディタの設定
DEFINE _EDITOR = vi

login.sql(ユーザーログインスクリプト)

個々のユーザーがカスタマイズ可能なログインスクリプトである。glogin.sql の後に実行され、glogin.sql の設定を上書きできる。

検索場所:
  1. 現在のディレクトリ(カレントディレクトリ)
  2. SQLPATH 環境変数で指定されたディレクトリ

login.sql の設定例を以下に示す。

-- login.sql
-- ユーザー個別の設定

-- 表示幅の拡張
SET LINESIZE 300
SET PAGESIZE 100

-- 長いテキストの表示設定
SET LONG 50000
SET LONGCHUNKSIZE 50000

-- 自動トレースの設定
-- SET AUTOTRACE ON EXPLAIN

-- よく使うカラム書式の設義
COLUMN owner FORMAT A20
COLUMN table_name FORMAT A30
COLUMN column_name FORMAT A30
COLUMN object_name FORMAT A30
COLUMN object_type FORMAT A20
COLUMN status FORMAT A10
COLUMN tablespace_name FORMAT A20

-- カスタムプロンプト(接続情報を表示)
SET SQLPROMPT "_USER'@'_CONNECT_IDENTIFIER _DATE> "

-- 起動メッセージ
PROMPT ========================================
PROMPT  SQL*Plus カスタム環境がロードされました
PROMPT ========================================

3.6 実行順序

SQL*Plus の起動時、設定ファイルは以下の順序で実行される。

1. $ORACLE_HOME/sqlplus/admin/glogin.sql  (グローバル設定)
2. ./login.sql または $SQLPATH/login.sql   (ユーザー設定)
3. コマンドラインで指定されたスクリプト     (@script.sql 指定時)

glogin.sql と login.sql で同じ SET コマンドが使用されている場合、login.sql の設定が優先される。

3.7 SQL*Plus の終了

-- 正常終了
SQL> EXIT

-- 明示的な終了コードを指定(シェルスクリプト連携時に有用)
SQL> EXIT 0
SQL> EXIT 1

-- SQL.SQLCODE の値を終了コードとして返す
SQL> EXIT SQL.SQLCODE

-- QUIT は EXIT と同義
SQL> QUIT

-- コミットせずに終了(ロールバック)
SQL> EXIT ROLLBACK

-- デフォルトの EXIT はコミットを実行する
SQL> EXIT COMMIT   -- デフォルト動作と同じ

3.8 コマンドラインからのスクリプト実行

# ログイン時にスクリプトを実行
sqlplus scott/tiger@ORCL @/home/oracle/scripts/daily_report.sql

# スクリプトにパラメータを渡す
sqlplus scott/tiger@ORCL @/home/oracle/scripts/check_table.sql EMPLOYEES HR

# サイレントモードでスクリプト実行(自動化向け)
sqlplus -S scott/tiger@ORCL @/home/oracle/scripts/batch_job.sql > /var/log/oracle/batch.log 2>&1

# ヒアドキュメントによるインライン実行
sqlplus -S scott/tiger@ORCL <<'ENDSQL'
SET PAGESIZE 0 FEEDBACK OFF
SELECT sysdate FROM dual;
EXIT;
ENDSQL

4. SQL*Plus コマンド体系

4.1 SQL コマンドと SQL*Plus コマンドの違い

SQL*Plus で入力されるコマンドは、大きく以下の3カテゴリに分類される。

カテゴリ説明終端文字
SQL文データベースに送信されるSQLセミコロン (;) または /SELECT, INSERT, CREATE
PL/SQLブロックPL/SQLプログラム/(単独行)BEGIN...END;
SQL*PlusコマンドSQL*Plus自体の制御コマンド改行(Enter)SET, COLUMN, SPOOL

重要な違いとして、SQL文はセミコロンまたはスラッシュで実行が開始されるのに対し、SQL*Plus コマンドは Enter キーを押した時点で即座に実行される。

-- SQL文はセミコロンで終了する
SQL> SELECT employee_id, first_name, last_name
  2  FROM employees
  3  WHERE department_id = 10;

-- SQL*Plus コマンドは Enter で即座に実行される(セミコロン不要)
SQL> SET LINESIZE 200
SQL> COLUMN first_name FORMAT A20

4.2 コマンドバッファ

SQLPlus は最後に入力された SQL文 または PL/SQLブロック をコマンドバッファに保持する。SQLPlus コマンドはバッファに格納されない。

-- SQL文を入力(バッファに格納される)
SQL> SELECT employee_id, first_name
  2  FROM employees
  3  WHERE department_id = 10;

-- バッファの内容を表示
SQL> LIST
  1  SELECT employee_id, first_name
  2  FROM employees
  3* WHERE department_id = 10

-- バッファの内容を再実行
SQL> RUN
  1  SELECT employee_id, first_name
  2  FROM employees
  3* WHERE department_id = 10

-- / でもバッファの内容を実行できる(LIST表示なし)
SQL> /

4.3 バッファ編集コマンド

バッファ内の SQL文を編集するためのコマンド群を以下に示す。

LIST (L) - バッファの表示

-- バッファ全体を表示
SQL> LIST
  1  SELECT employee_id, first_name
  2  FROM employees
  3* WHERE department_id = 10

-- 特定の行を表示
SQL> LIST 2
  2* FROM employees

-- 行範囲を表示
SQL> LIST 1 2
  1  SELECT employee_id, first_name
  2* FROM employees

-- 最終行を表示
SQL> LIST LAST
  3* WHERE department_id = 10

APPEND (A) - 現在行への追記

-- 現在行(*が付いた行)にテキストを追加
SQL> LIST 3
  3* WHERE department_id = 10
SQL> APPEND  ORDER BY employee_id
  3* WHERE department_id = 10 ORDER BY employee_id

-- 注意: APPEND の後にスペースが2つ必要(1つはコマンドとの区切り、1つは実際のスペース)

CHANGE (C) - テキストの置換

-- 現在行のテキストを置換
SQL> LIST 3
  3* WHERE department_id = 10
SQL> CHANGE /10/20/
  3* WHERE department_id = 20

-- 正規表現ではなく単純な文字列置換である
SQL> CHANGE /department_id/dept_id/
  3* WHERE dept_id = 20

DEL - 行の削除

-- 現在行を削除
SQL> DEL

-- 特定の行を削除
SQL> DEL 3

-- 行範囲を削除
SQL> DEL 2 3

-- 最終行を削除
SQL> DEL LAST

INPUT (I) - 行の挿入

-- 現在行の後に新しい行を挿入
SQL> LIST 2
  2* FROM employees
SQL> INPUT AND department_id = 10
SQL> LIST
  1  SELECT employee_id, first_name
  2  FROM employees
  3* AND department_id = 10

-- 複数行を入力(空行でINPUTモード終了)
SQL> INPUT
  4  ORDER BY employee_id
  5  
SQL>

4.4 ファイル操作コマンド

SAVE - バッファをファイルに保存

-- バッファの内容をファイルに保存
SQL> SAVE /home/oracle/scripts/query1.sql

-- 既存ファイルに上書き
SQL> SAVE /home/oracle/scripts/query1.sql REPLACE

-- 既存ファイルに追記
SQL> SAVE /home/oracle/scripts/query1.sql APPEND

GET - ファイルをバッファに読み込み

-- ファイルの内容をバッファに読み込む(実行はしない)
SQL> GET /home/oracle/scripts/query1.sql
  1  SELECT employee_id, first_name
  2  FROM employees
  3* WHERE department_id = 10

-- 読み込み後に実行
SQL> /

START (@) - ファイルを実行

-- スクリプトファイルを実行
SQL> START /home/oracle/scripts/daily_report.sql

-- @ は START の省略形
SQL> @/home/oracle/scripts/daily_report.sql

-- @@ は相対パスでスクリプトを実行(呼び出し元スクリプトのディレクトリ基準)
SQL> @@sub_script.sql

-- スクリプトにパラメータを渡す
SQL> @/home/oracle/scripts/check_table.sql EMPLOYEES HR
-- スクリプト内では &1 = 'EMPLOYEES', &2 = 'HR' として参照可能

EDIT - エディタでバッファを編集

-- デフォルトエディタでバッファ内容を編集
SQL> EDIT

-- ファイルを直接エディタで開く
SQL> EDIT /home/oracle/scripts/query1.sql

-- エディタの変更
SQL> DEFINE _EDITOR = vi
SQL> DEFINE _EDITOR = nano
SQL> DEFINE _EDITOR = "code --wait"   -- VS Code

4.5 RUN と / の違い

-- RUN: バッファの内容を表示してから実行する
SQL> RUN
  1  SELECT employee_id, first_name
  2  FROM employees
  3* WHERE department_id = 10

EMPLOYEE_ID FIRST_NAME
----------- --------------------
        100 Jennifer

-- /: バッファの内容を表示せずに実行する
SQL> /

EMPLOYEE_ID FIRST_NAME
----------- --------------------
        100 Jennifer

4.6 コマンドの省略形

SQL*Plus コマンドの多くは省略形が用意されている。

フルコマンド省略形説明
LISTLバッファ表示
APPENDA行への追記
CHANGECテキスト置換
INPUTI行の挿入
DELETEDEL行の削除
COLUMNCOLカラム書式
DESCRIBEDESCオブジェクト構造表示
EXECUTEEXECPL/SQL実行
DISCONNECTDISC切断
CLEARCL各種クリア
COMPUTECOMP集計計算
BREAKBREブレーク設定
TTITLETTIトップタイトル
BTITLEBTIボトムタイトル
SET LINESIZESET LIN行幅設定
SET PAGESIZESET PAGESページサイズ設定

4.7 DESCRIBE コマンド

テーブル、ビュー、シノニム、PL/SQLプログラムの構造を表示する。

-- テーブルの構造を表示
SQL> DESC employees
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 EMPLOYEE_ID                               NOT NULL NUMBER(6)
 FIRST_NAME                                         VARCHAR2(20)
 LAST_NAME                                 NOT NULL VARCHAR2(25)
 EMAIL                                     NOT NULL VARCHAR2(25)
 PHONE_NUMBER                                       VARCHAR2(20)
 HIRE_DATE                                 NOT NULL DATE
 JOB_ID                                    NOT NULL VARCHAR2(10)
 SALARY                                             NUMBER(8,2)
 COMMISSION_PCT                                     NUMBER(2,2)
 MANAGER_ID                                         NUMBER(6)
 DEPARTMENT_ID                                      NUMBER(4)

-- パッケージの構造を表示
SQL> DESC DBMS_OUTPUT
PROCEDURE DISABLE
PROCEDURE ENABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 BUFFER_SIZE                    NUMBER(38)              IN     DEFAULT
PROCEDURE GET_LINE
...

-- シノニムの解決
SQL> DESC all_tables

4.8 CLEAR コマンド

各種設定をクリアするコマンドである。

-- バッファをクリア
SQL> CLEAR BUFFER

-- カラム書式をすべてクリア
SQL> CLEAR COLUMNS

-- ブレーク設定をクリア
SQL> CLEAR BREAKS

-- COMPUTE 設定をクリア
SQL> CLEAR COMPUTES

-- 画面をクリア
SQL> CLEAR SCREEN

-- タイミング情報をクリア
SQL> CLEAR TIMING

-- SQL*Plus 設定の確認
SQL> SHOW ALL

5. 書式設定と表示制御

5.1 SET コマンドの概要

SET コマンドは SQL*Plus の動作を制御する最も重要なコマンドである。現在の設定値は SHOW コマンドで確認できる。

-- 全設定値の一覧表示
SQL> SHOW ALL

-- 特定の設定値を確認
SQL> SHOW LINESIZE
linesize 200

SQL> SHOW PAGESIZE
pagesize 50

5.2 表示幅とページ設定

SET LINESIZE (SET LIN)

1行あたりの最大表示文字数を設定する。デフォルトは80である。

-- 表示幅を200文字に設定
SQL> SET LINESIZE 200

-- ターミナル幅に合わせて設定
SQL> SET LINESIZE 300

-- 確認
SQL> SHOW LINESIZE
linesize 200

SET PAGESIZE (SET PAGES)

1ページあたりの行数を設定する。この値に達するとカラムヘッダーが再表示される。

-- ページサイズを50行に設定
SQL> SET PAGESIZE 50

-- ヘッダーの繰り返しを無効化(大量データ表示時)
SQL> SET PAGESIZE 0

-- ヘッダーのみ表示してデータのページ区切りを抑制
SQL> SET PAGESIZE 50000

5.3 フィードバックと情報表示

SET FEEDBACK

クエリの実行結果件数の表示を制御する。

-- フィードバックを無効化
SQL> SET FEEDBACK OFF

-- フィードバックを有効化(デフォルト)
SQL> SET FEEDBACK ON

-- 指定行数以上の場合のみフィードバック表示
SQL> SET FEEDBACK 10
-- 10行以上選択された場合のみ "XX rows selected." と表示

-- 例:フィードバック無効時
SQL> SET FEEDBACK OFF
SQL> SELECT * FROM departments WHERE department_id = 10;

DEPARTMENT_ID DEPARTMENT_NAME                MANAGER_ID LOCATION_ID
------------- ------------------------------ ---------- -----------
           10 Administration                        200        1700

-- 例:フィードバック有効時
SQL> SET FEEDBACK ON
SQL> SELECT * FROM departments WHERE department_id = 10;

DEPARTMENT_ID DEPARTMENT_NAME                MANAGER_ID LOCATION_ID
------------- ------------------------------ ---------- -----------
           10 Administration                        200        1700

1 row selected.

SET HEADING

カラムヘッダーの表示を制御する。

-- ヘッダーを非表示にする
SQL> SET HEADING OFF

-- ヘッダーを表示する(デフォルト)
SQL> SET HEADING ON

SET VERIFY

代入変数の展開前後の値を表示するかどうかを制御する。

-- 代入変数の展開表示を抑制
SQL> SET VERIFY OFF

-- 代入変数の展開を表示(デフォルト)
SQL> SET VERIFY ON
SQL> SELECT * FROM employees WHERE department_id = &dept_id;
old   1: SELECT * FROM employees WHERE department_id = &dept_id
new   1: SELECT * FROM employees WHERE department_id = 10

SET ECHO

スクリプトファイル実行時にコマンドをエコーバック(表示)するかどうかを制御する。

-- スクリプトのコマンドを表示する
SQL> SET ECHO ON

-- スクリプトのコマンドを表示しない(デフォルト)
SQL> SET ECHO OFF

5.4 実行時間と統計

SET TIMING

SQL文の実行時間を表示する。

SQL> SET TIMING ON
SQL> SELECT count(*) FROM employees;

  COUNT(*)
----------
       107

Elapsed: 00:00:00.02

SQL> SET TIMING OFF

SET AUTOTRACE

実行計画と実行統計を表示する(詳細は「パフォーマンス分析」セクションで解説)。

-- 実行計画のみ表示
SQL> SET AUTOTRACE ON EXPLAIN

-- 統計のみ表示
SQL> SET AUTOTRACE ON STATISTICS

-- 実行計画と統計の両方を表示
SQL> SET AUTOTRACE ON

-- 結果を表示せず実行計画と統計のみ表示
SQL> SET AUTOTRACE TRACEONLY

5.5 出力制御

SET SERVEROUTPUT

PL/SQL の DBMS_OUTPUT.PUT_LINE の出力を表示する。

-- サーバー出力を有効化
SQL> SET SERVEROUTPUT ON

-- バッファサイズを無制限に設定
SQL> SET SERVEROUTPUT ON SIZE UNLIMITED

-- 出力書式の設定
SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
SQL> SET SERVEROUTPUT ON FORMAT WORD_WRAPPED
SQL> SET SERVEROUTPUT ON FORMAT TRUNCATED

SET TRIMSPOOL

スプールファイルに出力する際、行末の空白を削除するかどうかを制御する。

-- 行末空白を削除(CSV出力時などに推奨)
SQL> SET TRIMSPOOL ON

-- 行末空白を保持(デフォルト)
SQL> SET TRIMSPOOL OFF

SET TRIMOUT

画面出力時の行末空白を制御する。

-- 画面出力の行末空白を削除
SQL> SET TRIMOUT ON

-- 画面出力の行末空白を保持(デフォルト)
SQL> SET TRIMOUT OFF

5.6 数値・区切り文字の設定

SET NUMFORMAT

数値のデフォルト表示書式を設定する。

-- 数値書式の設定
SQL> SET NUMFORMAT 999,999,999.99

SQL> SELECT salary FROM employees WHERE employee_id = 100;

       SALARY
-------------
   24,000.00

-- 書式をクリア
SQL> SET NUMFORMAT ""

SET COLSEP

カラム間の区切り文字を設定する。

-- カラム区切りをパイプに変更
SQL> SET COLSEP '|'

-- カラム区切りをカンマに変更(CSV出力向け)
SQL> SET COLSEP ','

-- カラム区切りをタブに変更(TSV出力向け)
SQL> SET COLSEP '	'

-- デフォルトに戻す(スペース1文字)
SQL> SET COLSEP ' '

SET NULL

NULL値の表示文字列を設定する。

-- NULL値を "(null)" と表示
SQL> SET NULL '(null)'

-- NULL値を "N/A" と表示
SQL> SET NULL 'N/A'

-- NULL値を空文字として表示(デフォルト)
SQL> SET NULL ''

5.7 その他の重要な SET コマンド

SET WRAP

行がLINESIZEを超えた場合の折り返し動作を制御する。

-- 超過部分を次の行に折り返す(デフォルト)
SQL> SET WRAP ON

-- 超過部分を切り捨てる
SQL> SET WRAP OFF

SET LONG / SET LONGCHUNKSIZE

LONG型やCLOB型のデータ表示に使用する最大バイト数を設定する。

-- LONGデータの最大表示長を設定
SQL> SET LONG 50000
SQL> SET LONGCHUNKSIZE 50000

-- DDL文の表示(DBMS_METADATA使用時に必要)
SQL> SET LONG 100000
SQL> SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES') FROM DUAL;

SET DEFINE

代入変数のプレフィックス文字を設定する。

-- デフォルトのプレフィックス(&)
SQL> SET DEFINE '&'

-- 代入変数機能を無効化(SQL中に & を含むデータを扱う場合)
SQL> SET DEFINE OFF

-- 代入変数のプレフィックスを変更
SQL> SET DEFINE '#'
SQL> SELECT * FROM employees WHERE department_id = #dept_id;

SET SQLBLANKLINES

SQL文中の空行を許可するかどうかを制御する。

-- SQL文中の空行を許可する
SQL> SET SQLBLANKLINES ON

-- SQL文中の空行で入力を終了する(デフォルト)
SQL> SET SQLBLANKLINES OFF

5.8 スクリプト向け推奨SET設定

バッチ処理やレポート生成向けの推奨設定テンプレートを以下に示す。

-- データ抽出(CSV出力)向け設定
SET LINESIZE 32767
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET VERIFY OFF
SET ECHO OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET COLSEP ','
SET NULL ''
SET WRAP OFF
SET TERMOUT OFF

-- レポート出力向け設定
SET LINESIZE 200
SET PAGESIZE 50
SET HEADING ON
SET FEEDBACK OFF
SET VERIFY OFF
SET ECHO OFF
SET TRIMSPOOL ON
SET NULL '(null)'

-- デバッグ向け設定
SET LINESIZE 200
SET PAGESIZE 50
SET HEADING ON
SET FEEDBACK ON
SET VERIFY ON
SET ECHO ON
SET TIMING ON
SET SERVEROUTPUT ON SIZE UNLIMITED
SET AUTOTRACE ON

6. COLUMN コマンドと出力フォーマット

6.1 COLUMN コマンドの基本

COLUMN コマンドは、SELECT文の出力カラムの表示書式を制御するための SQL*Plus コマンドである。

-- 基本構文
COLUMN column_name [option ...]

-- 現在のカラム設定を確認
SQL> COLUMN
SQL> COLUMN column_name

6.2 FORMAT オプション

カラムの表示書式を設定する最も使用頻度の高いオプションである。

文字列カラムの書式

-- 文字列カラムの幅を指定(A + 文字数)
SQL> COLUMN first_name FORMAT A15
SQL> COLUMN last_name FORMAT A20
SQL> COLUMN email FORMAT A30
SQL> COLUMN department_name FORMAT A25

-- 例
SQL> COLUMN first_name FORMAT A15
SQL> COLUMN last_name FORMAT A20
SQL> SELECT first_name, last_name FROM employees WHERE rownum <= 5;

FIRST_NAME      LAST_NAME
--------------- --------------------
Steven          King
Neena           Kochhar
Lex             De Haan
Alexander       Hunold
Bruce           Ernst

数値カラムの書式

-- 基本的な数値書式
SQL> COLUMN salary FORMAT 999,999.99
SQL> COLUMN employee_id FORMAT 99999
SQL> COLUMN commission_pct FORMAT 0.99

-- 通貨記号付き
SQL> COLUMN salary FORMAT $999,999.99
SQL> COLUMN salary FORMAT L999,999.99   -- ローカル通貨記号

-- 数値書式記号の一覧
-- 9: 数字位置(先頭ゼロは空白)
-- 0: 数字位置(先頭ゼロを表示)
-- $: ドル記号
-- L: ローカル通貨記号
-- .: 小数点
-- ,: 桁区切り
-- MI: 末尾にマイナス記号
-- PR: 負数を<>で囲む
-- EEEE: 科学的記数法
-- V: 10のべき乗で乗算
-- B: ゼロを空白で表示

-- 書式の例
SQL> COLUMN amount FORMAT 999,999,999.99
SQL> COLUMN rate FORMAT 0.0000
SQL> COLUMN large_num FORMAT 9.999EEEE
SQL> COLUMN negative_val FORMAT 999,999MI

6.3 HEADING オプション

カラムヘッダーのテキストを変更する。

-- ヘッダーの変更
SQL> COLUMN employee_id HEADING '社員番号'
SQL> COLUMN first_name HEADING '名前' FORMAT A15
SQL> COLUMN last_name HEADING '姓' FORMAT A20
SQL> COLUMN salary HEADING '給与' FORMAT 999,999

-- 複数行ヘッダー(| で改行)
SQL> COLUMN hire_date HEADING '入社|日付'
SQL> COLUMN department_id HEADING '部門|番号'

SQL> SELECT employee_id, first_name, last_name, salary, hire_date, department_id
  2  FROM employees WHERE rownum <= 3;

               入社   部門
社員番号 名前            姓                   給与 日付     番号
-------- --------------- -------------------- -------- --------- ------
     100 Steven          King                  24,000 17-JUN-03     90
     101 Neena           Kochhar               17,000 21-SEP-05     90
     102 Lex             De Haan               17,000 13-JAN-01     90

6.4 その他の COLUMN オプション

JUSTIFY - ヘッダーの配置

-- ヘッダーを左揃え
SQL> COLUMN salary HEADING '給与' FORMAT 999,999 JUSTIFY LEFT

-- ヘッダーを右揃え
SQL> COLUMN department_name HEADING '部門名' JUSTIFY RIGHT

-- ヘッダーを中央揃え
SQL> COLUMN status HEADING 'ステータス' JUSTIFY CENTER

WORD_WRAPPED / WRAPPED / TRUNCATED - 長文テキストの処理

-- 語句単位で折り返し
SQL> COLUMN comments FORMAT A40 WORD_WRAPPED

-- 文字単位で折り返し
SQL> COLUMN comments FORMAT A40 WRAPPED

-- 超過部分を切り捨て
SQL> COLUMN comments FORMAT A40 TRUNCATED

NULL - NULL値の表示

-- 特定カラムのNULL表示を設定
SQL> COLUMN commission_pct NULL '対象外'
SQL> COLUMN manager_id NULL '(なし)'

PRINT / NOPRINT - カラムの表示/非表示

-- カラムを非表示にする(BREAK/COMPUTEでは使用可能)
SQL> COLUMN department_id NOPRINT

-- カラムを表示に戻す
SQL> COLUMN department_id PRINT

NEW_VALUE / OLD_VALUE - タイトルでの変数利用

-- カラム値をタイトル変数として使用
SQL> COLUMN report_date NEW_VALUE v_report_date
SQL> SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD') AS report_date FROM dual;
SQL> TTITLE LEFT '日次レポート - ' v_report_date

6.5 COLUMN 設定のクリア

-- 特定カラムの設定をクリア
SQL> COLUMN first_name CLEAR

-- すべてのカラム設定をクリア
SQL> CLEAR COLUMNS

6.6 BREAK コマンド

BREAK コマンドは、指定したカラムの値が変わるタイミングで区切り線や改ページを挿入するコマンドである。

-- 部門ごとに区切り
SQL> BREAK ON department_id

-- 部門ごとに空行を挿入
SQL> BREAK ON department_id SKIP 1

-- 部門ごとに改ページ
SQL> BREAK ON department_id SKIP PAGE

-- 複数カラムでのブレーク
SQL> BREAK ON department_id SKIP 1 ON job_id SKIP 1

-- レポート全体にブレーク
SQL> BREAK ON REPORT

-- 例: 部門別社員一覧
SQL> BREAK ON department_id SKIP 1
SQL> SELECT department_id, employee_id, last_name, salary
  2  FROM employees
  3  WHERE department_id IN (10, 20, 30)
  4  ORDER BY department_id, employee_id;

DEPARTMENT_ID EMPLOYEE_ID LAST_NAME                     SALARY
------------- ----------- ------------------------- ----------
           10         200 Whalen                          4400

           20         201 Hartstein                      13000
                      202 Fay                             6000

           30         114 Raphaely                       11000
                      115 Khoo                            3100
                      116 Baida                           2900

6.7 COMPUTE コマンド

COMPUTE コマンドは、BREAK と連動して集計値を計算・表示するコマンドである。

-- 部門ごとの給与合計を計算
SQL> BREAK ON department_id SKIP 1
SQL> COMPUTE SUM OF salary ON department_id

-- 利用可能な集計関数
-- SUM     : 合計
-- AVG     : 平均
-- MIN     : 最小値
-- MAX     : 最大値
-- COUNT   : 件数
-- NUM     : NULL以外の件数
-- STD     : 標準偏差
-- VAR     : 分散

-- 複数の集計
SQL> COMPUTE SUM AVG MIN MAX OF salary ON department_id

-- レポート全体の集計
SQL> BREAK ON department_id SKIP 1 ON REPORT
SQL> COMPUTE SUM OF salary ON department_id
SQL> COMPUTE SUM AVG OF salary ON REPORT

-- 実行例
SQL> BREAK ON department_id SKIP 1 ON REPORT
SQL> COMPUTE SUM LABEL '部門計' OF salary ON department_id
SQL> COMPUTE SUM LABEL '総計' AVG LABEL '平均' OF salary ON REPORT

SQL> SELECT department_id, employee_id, last_name, salary
  2  FROM employees
  3  WHERE department_id IN (10, 20)
  4  ORDER BY department_id;

DEPARTMENT_ID EMPLOYEE_ID LAST_NAME                     SALARY
------------- ----------- ------------------------- ----------
           10         200 Whalen                          4400
*********                                           ----------
部門計                                                    4400

           20         201 Hartstein                      13000
                      202 Fay                             6000
*********                                           ----------
部門計                                                   19000

                                                    ----------
総計                                                     23400
                                                    ----------
平均                                                      7800

6.8 設定の保存と復元

-- 現在のすべての設定をファイルに保存
SQL> STORE SET /home/oracle/scripts/my_settings.sql REPLACE

-- 保存した設定を復元
SQL> @/home/oracle/scripts/my_settings.sql

-- レポート設定のテンプレート例
-- report_setup.sql
CLEAR COLUMNS
CLEAR BREAKS
CLEAR COMPUTES
SET LINESIZE 200
SET PAGESIZE 50
SET FEEDBACK OFF
COLUMN employee_id HEADING '社員ID' FORMAT 99999
COLUMN first_name HEADING '名前' FORMAT A15
COLUMN last_name HEADING '姓' FORMAT A20
COLUMN salary HEADING '給与' FORMAT $999,999.99
COLUMN department_name HEADING '部門名' FORMAT A25

7. スプールとレポート作成

7.1 SPOOL コマンド

SPOOL コマンドは、SQL*Plus の画面出力をファイルに保存するためのコマンドである。

-- スプールの開始
SQL> SPOOL /home/oracle/reports/output.txt

-- スプールの停止
SQL> SPOOL OFF

-- 既存ファイルへの追記
SQL> SPOOL /home/oracle/reports/output.txt APPEND

-- 既存ファイルの上書き
SQL> SPOOL /home/oracle/reports/output.txt REPLACE

-- 現在のスプール状態を確認
SQL> SHOW SPOOL

スプール出力の基本パターン

-- テキストレポートの出力
SPOOL /home/oracle/reports/employee_report.txt
SET LINESIZE 200
SET PAGESIZE 50
SET FEEDBACK OFF

TTITLE CENTER '社員一覧レポート' SKIP 2
BTITLE CENTER '-- ページ終了 --'

SELECT employee_id, first_name, last_name, salary, department_id
FROM employees
ORDER BY department_id, employee_id;

SPOOL OFF
TTITLE OFF
BTITLE OFF

7.2 CSV ファイルの出力

-- CSV出力の設定
SET LINESIZE 32767
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET VERIFY OFF
SET TRIMSPOOL ON
SET COLSEP ','
SET NULL ''
SET WRAP OFF
SET TERMOUT OFF

SPOOL /home/oracle/exports/employees.csv

-- ヘッダー行の出力
SELECT 'EMPLOYEE_ID,FIRST_NAME,LAST_NAME,EMAIL,SALARY,DEPARTMENT_ID' FROM dual;

-- データ行の出力
SELECT employee_id || ',' ||
       first_name || ',' ||
       last_name || ',' ||
       email || ',' ||
       salary || ',' ||
       department_id
FROM employees
ORDER BY employee_id;

SPOOL OFF

-- SET値を元に戻す
SET TERMOUT ON
SET HEADING ON
SET FEEDBACK ON
SET PAGESIZE 50
SET COLSEP ' '

7.3 より洗練された CSV 出力

文字列中にカンマやダブルクォートを含むデータに対応するには、以下のようにダブルクォートで囲む。

SET LINESIZE 32767
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON
SET WRAP OFF
SET TERMOUT OFF

SPOOL /home/oracle/exports/employees_quoted.csv

SELECT '"' || employee_id || '","' ||
       REPLACE(first_name, '"', '""') || '","' ||
       REPLACE(last_name, '"', '""') || '","' ||
       email || '","' ||
       NVL(TO_CHAR(salary), '') || '","' ||
       NVL(TO_CHAR(department_id), '') || '"'
FROM employees
ORDER BY employee_id;

SPOOL OFF
SET TERMOUT ON

7.4 TTITLE / BTITLE(ページヘッダー/フッター)

TTITLE(トップタイトル)と BTITLE(ボトムタイトル)は、各ページの上部と下部にヘッダー・フッターを表示するコマンドである。

-- 基本的なタイトル設定
SQL> TTITLE '社員一覧レポート'
SQL> BTITLE 'CONFIDENTIAL'

-- 配置の指定
SQL> TTITLE LEFT '部門別給与レポート' CENTER '2026年4月' RIGHT 'Page: ' FORMAT 999 SQL.PNO
SQL> BTITLE CENTER '--- End of Page ---'

-- 複数行のタイトル
SQL> TTITLE LEFT '============================================' -
>    SKIP 1 CENTER '人事部 月次給与レポート' -
>    SKIP 1 CENTER '作成日: 2026-04-13' -
>    SKIP 1 LEFT '============================================' -
>    SKIP 2

-- 変数の使用(NEW_VALUE との連携)
SQL> COLUMN today_date NEW_VALUE v_date NOPRINT
SQL> SELECT TO_CHAR(SYSDATE, 'YYYY/MM/DD') AS today_date FROM dual;
SQL> TTITLE LEFT 'レポート作成日: ' v_date CENTER '社員レポート' RIGHT 'Page ' SQL.PNO

TTITLE / BTITLE の書式要素

要素説明
LEFT左揃え
CENTER中央揃え
RIGHT右揃え
SKIP nn行スキップ
SKIP PAGE改ページ
TAB nn文字分タブ移動
FORMAT fmt次の値の書式
SQL.PNOページ番号
SQL.LNO行番号
SQL.USER現在のユーザー
SQL.RELEASEOracleバージョン

7.5 REPHEADER / REPFOOTER

REPHEADER(レポートヘッダー)と REPFOOTER(レポートフッター)は、レポート全体の先頭と末尾に一度だけ表示されるヘッダー・フッターである。

-- レポートヘッダー(レポートの冒頭に1回表示)
SQL> REPHEADER CENTER '=============================' -
>    SKIP 1 CENTER '年次人事レポート 2026年度' -
>    SKIP 1 CENTER '=============================' -
>    SKIP 2

-- レポートフッター(レポートの末尾に1回表示)
SQL> REPFOOTER CENTER '--- レポート終了 ---' -
>    SKIP 1 CENTER '本レポートは機密文書です'

-- レポートヘッダー/フッターの無効化
SQL> REPHEADER OFF
SQL> REPFOOTER OFF

7.6 HTML レポートの出力

SQL*Plus は SET MARKUP HTML ON を使用して、HTML形式のレポートを生成できる。

-- HTML出力の有効化
SET MARKUP HTML ON SPOOL ON PREFORMAT OFF ENTMAP ON

SPOOL /home/oracle/reports/employee_report.html

TTITLE CENTER '<h1>社員一覧レポート</h1>'

SELECT employee_id, first_name, last_name, salary, department_id
FROM employees
WHERE department_id = 10
ORDER BY employee_id;

SPOOL OFF
SET MARKUP HTML OFF

コマンドラインからの HTML 生成

# コマンドラインオプションで HTML モードを指定
sqlplus -S -M "HTML ON TABLE 'BORDER=1 CELLSPACING=0' BODY 'BGCOLOR=#FFFFFF'" \
  scott/tiger@ORCL <<EOF
SPOOL /home/oracle/reports/report.html
SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE rownum <= 20;
SPOOL OFF
EXIT
EOF

7.7 完全なレポートスクリプトの例

-- daily_salary_report.sql
-- 部門別給与サマリーレポート

-- 初期設定
SET LINESIZE 120
SET PAGESIZE 40
SET FEEDBACK OFF
SET VERIFY OFF
SET ECHO OFF

-- 日付の取得
COLUMN report_date NEW_VALUE v_date NOPRINT
SELECT TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI') AS report_date FROM dual;

-- タイトル設定
TTITLE LEFT '部門別給与サマリーレポート' -
       RIGHT '作成日: ' v_date -
       SKIP 1 LEFT '================================================================' -
       SKIP 1

BTITLE CENTER 'Page ' FORMAT 99 SQL.PNO ' / CONFIDENTIAL'

REPHEADER CENTER '=========================================' -
         SKIP 1 CENTER '   人事部 月次給与レポート   ' -
         SKIP 1 CENTER '=========================================' -
         SKIP 2

REPFOOTER SKIP 2 CENTER '--- レポート終了 ---'

-- カラム書式
COLUMN department_name HEADING '部門名' FORMAT A25
COLUMN employee_count  HEADING '社員数' FORMAT 9,999
COLUMN min_salary      HEADING '最低給与' FORMAT $999,999
COLUMN max_salary      HEADING '最高給与' FORMAT $999,999
COLUMN avg_salary      HEADING '平均給与' FORMAT $999,999.99
COLUMN total_salary    HEADING '給与合計' FORMAT $9,999,999

-- ブレーク設定
BREAK ON REPORT
COMPUTE SUM LABEL '*** 全社計 ***' OF employee_count total_salary ON REPORT
COMPUTE AVG LABEL '*** 全社平均 ***' OF avg_salary ON REPORT

-- スプール開始
SPOOL /home/oracle/reports/salary_summary.txt

-- メインクエリ
SELECT d.department_name,
       COUNT(e.employee_id) AS employee_count,
       MIN(e.salary) AS min_salary,
       MAX(e.salary) AS max_salary,
       AVG(e.salary) AS avg_salary,
       SUM(e.salary) AS total_salary
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_name
ORDER BY d.department_name;

-- スプール終了とクリーンアップ
SPOOL OFF
TTITLE OFF
BTITLE OFF
REPHEADER OFF
REPFOOTER OFF
CLEAR COLUMNS
CLEAR BREAKS
CLEAR COMPUTES
SET FEEDBACK ON

8. 変数と代入変数

8.1 代入変数(置換変数)の基本

SQL*Plus の代入変数は、SQL文やPL/SQLブロック内にプレースホルダーを配置し、実行時に値を置換する機能である。

& 変数(単一アンパサンド)

毎回値の入力を求める変数である。

-- 実行のたびに値の入力を求められる
SQL> SELECT employee_id, first_name, last_name, salary
  2  FROM employees
  3  WHERE department_id = &dept_id;
Enter value for dept_id: 10
old   3: WHERE department_id = &dept_id
new   3: WHERE department_id = 10

EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        200 Jennifer             Whalen                          4400

&& 変数(二重アンパサンド)

初回のみ入力を求め、以降は同じ値を再利用する変数である。内部的には DEFINE コマンドで変数が定義される。

-- 初回のみ入力を求められる
SQL> SELECT employee_id, first_name, salary
  2  FROM employees
  3  WHERE department_id = &&dept_id;
Enter value for dept_id: 20

-- 2回目以降は同じ値が使用される
SQL> SELECT COUNT(*) FROM employees WHERE department_id = &&dept_id;
-- 入力を求められず、20が使用される

-- 定義を解除するには UNDEFINE を使用
SQL> UNDEFINE dept_id

8.2 スクリプトパラメータ (&1, &2, ...)

スクリプトファイルにパラメータを渡す場合、位置パラメータとして &1, &2, &3 ... が使用される。

-- check_employee.sql
-- 使用方法: @check_employee.sql <employee_id> <schema>
SET VERIFY OFF
SET FEEDBACK ON

PROMPT 社員ID &1 の情報を &2 スキーマから検索します...

SELECT employee_id, first_name, last_name, salary, department_id
FROM &2..employees
WHERE employee_id = &1;

-- 実行
-- SQL> @check_employee.sql 100 HR

8.3 DEFINE コマンド

DEFINE コマンドは、SQL*Plus 変数を明示的に定義するコマンドである。

-- 変数の定義
SQL> DEFINE dept_id = 10
SQL> DEFINE schema_name = 'HR'
SQL> DEFINE output_dir = '/home/oracle/reports'

-- 変数の確認
SQL> DEFINE dept_id
DEFINE DEPT_ID             = "10" (CHAR)

-- すべての定義済み変数を表示
SQL> DEFINE
DEFINE _DATE           = "13-APR-26" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "ORCL" (CHAR)
DEFINE _USER           = "SCOTT" (CHAR)
DEFINE _PRIVILEGE      = "" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1902000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c..." (CHAR)
DEFINE _O_RELEASE      = "1902000000" (CHAR)
DEFINE DEPT_ID         = "10" (CHAR)
DEFINE SCHEMA_NAME     = "HR" (CHAR)

-- 変数の使用
SQL> SELECT * FROM employees WHERE department_id = &dept_id;

-- 変数の削除
SQL> UNDEFINE dept_id
SQL> UNDEFINE schema_name

事前定義変数(システム変数)

SQL*Plus には接続情報に基づいて自動的に定義される変数がある。

変数名説明
_USER現在のユーザー名SCOTT
_CONNECT_IDENTIFIER接続識別子ORCL
_DATE現在の日付13-APR-26
_PRIVILEGE接続権限AS SYSDBA
_SQLPLUS_RELEASESQL*Plus のリリース番号1902000000
_EDITORデフォルトエディタvi
_O_VERSIONOracle Database のバージョン文字列Oracle Database 19c...
_O_RELEASEOracle Database のリリース番号1902000000

8.4 ACCEPT コマンド

ACCEPT コマンドは、ユーザーに対話的に値の入力を求め、変数に格納するコマンドである。

-- 基本的な入力要求
SQL> ACCEPT dept_id NUMBER PROMPT '部門番号を入力してください: '
部門番号を入力してください: 10

-- 文字列入力
SQL> ACCEPT emp_name CHAR PROMPT '社員名を入力してください: '
社員名を入力してください: King

-- 日付入力(書式チェック付き)
SQL> ACCEPT start_date DATE FORMAT 'YYYY-MM-DD' PROMPT '開始日 (YYYY-MM-DD): '
開始日 (YYYY-MM-DD): 2026-01-01

-- パスワード入力(入力内容を非表示)
SQL> ACCEPT user_pass CHAR PROMPT 'パスワード: ' HIDE
パスワード: ********

-- デフォルト値付き
SQL> ACCEPT dept_id NUMBER DEFAULT 10 PROMPT '部門番号 [10]: '
部門番号 [10]:           -- Enter を押すとデフォルト値 10 が使用される

8.5 PROMPT コマンド

画面にメッセージを表示するコマンドである。

-- メッセージの表示
SQL> PROMPT 処理を開始します...
処理を開始します...

SQL> PROMPT
    -- 空行を表示

-- スクリプトでの活用例
PROMPT ========================================
PROMPT  データベースメンテナンススクリプト
PROMPT  実行日: &_DATE
PROMPT ========================================
PROMPT
ACCEPT confirm CHAR PROMPT '続行しますか? (Y/N): '

8.6 バインド変数

バインド変数は、SQL*Plus セッション内で PL/SQL と SQL の間でデータを受け渡すための変数である。代入変数(テキスト置換)とは異なり、バインド変数はデータベースエンジンに直接渡される。

VARIABLE コマンドによるバインド変数の宣言

-- バインド変数の宣言
SQL> VARIABLE emp_count NUMBER
SQL> VARIABLE emp_name VARCHAR2(50)
SQL> VARIABLE emp_salary NUMBER
SQL> VARIABLE result_msg VARCHAR2(200)
SQL> VARIABLE ref_cursor REFCURSOR

-- 利用可能なデータ型
-- NUMBER
-- VARCHAR2(size)
-- CHAR(size)
-- NCHAR(size)
-- NVARCHAR2(size)
-- CLOB
-- NCLOB
-- BLOB
-- BFILE
-- REFCURSOR

バインド変数への値の設定

-- PL/SQL ブロック内で値を設定
SQL> VARIABLE emp_count NUMBER
SQL> BEGIN
  2    SELECT COUNT(*) INTO :emp_count FROM employees;
  3  END;
  4  /

PL/SQL procedure successfully completed.

-- バインド変数の値を表示
SQL> PRINT emp_count

 EMP_COUNT
----------
       107

-- EXECUTE(EXEC)による簡易的な値の設定
SQL> VARIABLE emp_name VARCHAR2(50)
SQL> EXEC :emp_name := 'King'

PL/SQL procedure successfully completed.

SQL> PRINT emp_name

EMP_NAME
--------------------------------------------------
King

バインド変数を SQL 文で使用

-- バインド変数を WHERE 句で使用
SQL> VARIABLE dept_id NUMBER
SQL> EXEC :dept_id := 10

SQL> SELECT employee_id, first_name, last_name
  2  FROM employees
  3  WHERE department_id = :dept_id;

EMPLOYEE_ID FIRST_NAME           LAST_NAME
----------- -------------------- -------------------------
        200 Jennifer             Whalen

REFCURSOR バインド変数

-- REFCURSORの使用例
SQL> VARIABLE rc REFCURSOR

SQL> BEGIN
  2    OPEN :rc FOR
  3      SELECT employee_id, first_name, salary
  4      FROM employees
  5      WHERE department_id = 10;
  6  END;
  7  /

PL/SQL procedure successfully completed.

SQL> PRINT rc

EMPLOYEE_ID FIRST_NAME               SALARY
----------- -------------------- ----------
        200 Jennifer                   4400

8.7 代入変数とバインド変数の使い分け

特徴代入変数 (&)バインド変数 (:)
置換方式テキスト置換(クライアント側)パラメータバインド(サーバー側)
用途テーブル名、カラム名、構文要素WHERE句の条件値
SQLインジェクション脆弱性あり安全
共有カーソル毎回ハードパースソフトパース(再利用)
宣言DEFINE または暗黙VARIABLE
参照&var または &&var:var
PL/SQL連携不可可能
-- 代入変数が適切な場面(構文要素の動的指定)
SQL> DEFINE table_name = employees
SQL> SELECT COUNT(*) FROM &table_name;

-- バインド変数が適切な場面(条件値の動的指定)
SQL> VARIABLE salary_threshold NUMBER
SQL> EXEC :salary_threshold := 10000
SQL> SELECT * FROM employees WHERE salary > :salary_threshold;

9. スクリプティングと自動化

9.1 スクリプトファイルの基本構造

SQLPlus スクリプトは、SQL文、PL/SQLブロック、SQLPlusコマンドを組み合わせたテキストファイルである。

-- template_script.sql
-- ====================================================
-- スクリプト名: template_script.sql
-- 概要: バッチ処理テンプレート
-- 作成者: DBA Team
-- 作成日: 2026-04-13
-- パラメータ: &1 = スキーマ名
-- ====================================================

-- 初期設定
SET ECHO OFF
SET VERIFY OFF
SET FEEDBACK OFF
SET HEADING ON
SET LINESIZE 200
SET PAGESIZE 50
SET SERVEROUTPUT ON SIZE UNLIMITED
SET TIMING ON

-- エラーハンドリング
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
WHENEVER OSERROR EXIT 9 ROLLBACK

-- ログ出力の開始
SPOOL /var/log/oracle/template_script_&1..log

PROMPT ========================================
PROMPT 処理開始: &_DATE
PROMPT 対象スキーマ: &1
PROMPT ========================================

-- メイン処理
-- (ここにSQLやPL/SQLブロックを記述)

PROMPT ========================================
PROMPT 処理完了: &_DATE
PROMPT ========================================

-- ログ出力の終了
SPOOL OFF

EXIT 0

9.2 HOST コマンド

HOST コマンド(または !)を使用して、SQL*Plus からOSコマンドを実行できる。

-- OS コマンドの実行
SQL> HOST ls -la /home/oracle/scripts/

-- ! は HOST の省略形(Unix/Linux)
SQL> ! ls -la /home/oracle/scripts/
SQL> ! date
SQL> ! df -h

-- 環境変数の確認
SQL> HOST echo $ORACLE_HOME
SQL> HOST echo $ORACLE_SID

-- ファイル操作
SQL> HOST mkdir -p /home/oracle/exports/$(date +%Y%m%d)

-- OS コマンドの結果をスクリプトで活用する例
SQL> HOST date +%Y%m%d > /tmp/today.txt

9.3 EXIT / QUIT コマンドと戻り値

-- 正常終了(戻り値 0)
EXIT 0

-- 異常終了(戻り値 1)
EXIT 1

-- SQL.SQLCODE の値を戻り値として使用
EXIT SQL.SQLCODE

-- バインド変数の値を戻り値として使用
VARIABLE retcode NUMBER
BEGIN
  -- 処理結果に応じて戻り値を設定
  :retcode := 0;  -- 成功
EXCEPTION
  WHEN OTHERS THEN
    :retcode := 1;  -- 失敗
END;
/
EXIT :retcode

-- コミット/ロールバックの制御
EXIT COMMIT      -- コミットして終了(デフォルト)
EXIT ROLLBACK    -- ロールバックして終了

9.4 WHENEVER SQLERROR / WHENEVER OSERROR

SQL エラーやOSエラー発生時の動作を制御する。

-- SQLエラー発生時にスクリプトを終了(ロールバック)
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

-- SQLエラー発生時に処理を継続
WHENEVER SQLERROR CONTINUE

-- SQLエラー発生時にコミットして終了
WHENEVER SQLERROR EXIT SQL.SQLCODE COMMIT

-- エラーメッセージを表示して継続
WHENEVER SQLERROR CONTINUE NONE

-- OSエラー発生時の制御
WHENEVER OSERROR EXIT 9 ROLLBACK
WHENEVER OSERROR CONTINUE

-- 使い分けの例
-- 重要な処理ではエラー即停止
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
INSERT INTO critical_table VALUES (...);
COMMIT;

-- 軽微な処理ではエラーを無視
WHENEVER SQLERROR CONTINUE
DROP TABLE temp_table;  -- テーブルが存在しなくてもエラーにならない

-- 再度エラー即停止に戻す
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
CREATE TABLE temp_table (...);

9.5 シェルスクリプトとの連携

基本的なシェルスクリプト連携

#!/bin/bash
# daily_batch.sh - 日次バッチ処理

# 環境設定
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export ORACLE_SID=ORCL
export PATH=$ORACLE_HOME/bin:$PATH
export NLS_LANG=JAPANESE_JAPAN.AL32UTF8

# ログファイル設定
LOG_DIR=/var/log/oracle/batch
LOG_FILE=${LOG_DIR}/daily_batch_$(date +%Y%m%d_%H%M%S).log
SCRIPT_DIR=/home/oracle/scripts

# ログディレクトリの作成
mkdir -p ${LOG_DIR}

# SQL*Plus の実行
sqlplus -S / as sysdba <<'ENDSQL' >> ${LOG_FILE} 2>&1
SET ECHO ON
SET TIMING ON
SET SERVEROUTPUT ON SIZE UNLIMITED
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

-- 統計情報の収集
EXEC DBMS_STATS.GATHER_SCHEMA_STATS('HR');

-- 古いデータの削除
DELETE FROM hr.audit_log WHERE created_date < SYSDATE - 90;
COMMIT;

EXIT 0;
ENDSQL

# 戻り値のチェック
RC=$?
if [ ${RC} -ne 0 ]; then
    echo "[ERROR] SQL*Plus がエラーコード ${RC} で終了しました" >> ${LOG_FILE}
    # メール通知
    mail -s "バッチ処理エラー: daily_batch" dba@example.com < ${LOG_FILE}
    exit ${RC}
fi

echo "[INFO] バッチ処理が正常に完了しました" >> ${LOG_FILE}
exit 0

パラメータの受け渡し

#!/bin/bash
# export_table.sh - テーブルデータのエクスポート

TABLE_NAME=$1
SCHEMA_NAME=${2:-HR}
OUTPUT_DIR=/home/oracle/exports/$(date +%Y%m%d)
OUTPUT_FILE=${OUTPUT_DIR}/${TABLE_NAME}.csv

mkdir -p ${OUTPUT_DIR}

sqlplus -S ${SCHEMA_NAME}/password@ORCL <<ENDSQL > ${OUTPUT_FILE}
SET LINESIZE 32767
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON
SET COLSEP ','

SELECT * FROM ${TABLE_NAME};

EXIT 0;
ENDSQL

RC=$?
if [ ${RC} -eq 0 ]; then
    echo "エクスポート完了: ${OUTPUT_FILE} ($(wc -l < ${OUTPUT_FILE}) 行)"
else
    echo "エクスポートエラー: テーブル ${TABLE_NAME}"
    exit ${RC}
fi

9.6 条件付き実行パターン

SQL*Plus 自体には IF-THEN-ELSE のような制御構文はないが、PL/SQL と組み合わせることで条件付き実行を実現できる。

-- パターン1: PL/SQL による条件分岐
SET SERVEROUTPUT ON
DECLARE
    v_count NUMBER;
BEGIN
    SELECT COUNT(*) INTO v_count FROM user_tables WHERE table_name = 'TEMP_TABLE';
    IF v_count > 0 THEN
        EXECUTE IMMEDIATE 'DROP TABLE temp_table';
        DBMS_OUTPUT.PUT_LINE('テーブル TEMP_TABLE を削除しました');
    ELSE
        DBMS_OUTPUT.PUT_LINE('テーブル TEMP_TABLE は存在しません');
    END IF;
END;
/

-- パターン2: COLUMN NEW_VALUE を使った条件分岐
COLUMN do_create NEW_VALUE v_do_create
SELECT CASE WHEN COUNT(*) = 0 THEN 'create_table.sql'
            ELSE 'skip.sql'
       END AS do_create
FROM user_tables
WHERE table_name = 'MY_TABLE';

@&v_do_create

-- パターン3: WHENEVER SQLERROR を活用した条件付き処理
WHENEVER SQLERROR CONTINUE
DROP TABLE temp_results;
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
CREATE TABLE temp_results AS
SELECT * FROM employees WHERE 1=0;

9.7 複数データベースへの接続と処理

-- multi_db_check.sql
-- 複数データベースの状態チェック

SET ECHO OFF
SET VERIFY OFF
SET FEEDBACK OFF
SET SERVEROUTPUT ON

SPOOL /home/oracle/reports/multi_db_status.txt

-- データベース1のチェック
PROMPT === データベース PROD1 ===
CONNECT admin/password@PROD1
SELECT instance_name, status, database_status FROM v$instance;
SELECT name, open_mode FROM v$database;
DISCONNECT

-- データベース2のチェック
PROMPT === データベース PROD2 ===
CONNECT admin/password@PROD2
SELECT instance_name, status, database_status FROM v$instance;
SELECT name, open_mode FROM v$database;
DISCONNECT

-- データベース3のチェック
PROMPT === データベース PROD3 ===
CONNECT admin/password@PROD3
SELECT instance_name, status, database_status FROM v$instance;
SELECT name, open_mode FROM v$database;
DISCONNECT

SPOOL OFF
EXIT 0

10. PL/SQL との連携

10.1 無名PL/SQLブロックの実行

SQL*Plus から PL/SQL の無名ブロック(Anonymous Block)を直接実行できる。

-- 基本的な無名ブロック
SQL> SET SERVEROUTPUT ON SIZE UNLIMITED
SQL> BEGIN
  2    DBMS_OUTPUT.PUT_LINE('Hello, SQL*Plus!');
  3    DBMS_OUTPUT.PUT_LINE('現在時刻: ' || TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
  4  END;
  5  /

Hello, SQL*Plus!
現在時刻: 2026-04-13 10:30:00

PL/SQL procedure successfully completed.

重要な点として、PL/SQL ブロックの終了は /(スラッシュ)単独行であり、セミコロンではない。END; のセミコロンは PL/SQL の構文の一部であり、ブロック全体の実行は / で開始される。

10.2 SET SERVEROUTPUT の詳細

DBMS_OUTPUT パッケージの出力を SQL*Plus で表示するには、SET SERVEROUTPUT ON が必要である。

-- 基本的な有効化
SQL> SET SERVEROUTPUT ON

-- バッファサイズを指定(デフォルトは 20000 バイト)
SQL> SET SERVEROUTPUT ON SIZE 1000000

-- バッファサイズを無制限に設定(推奨)
SQL> SET SERVEROUTPUT ON SIZE UNLIMITED

-- 出力書式の制御
SQL> SET SERVEROUTPUT ON FORMAT WRAPPED       -- 文字単位で折り返し
SQL> SET SERVEROUTPUT ON FORMAT WORD_WRAPPED  -- 語句単位で折り返し(推奨)
SQL> SET SERVEROUTPUT ON FORMAT TRUNCATED     -- 超過部分を切り捨て

10.3 DBMS_OUTPUT の活用パターン

-- 処理進捗の表示
SET SERVEROUTPUT ON SIZE UNLIMITED
DECLARE
    v_total NUMBER;
    v_processed NUMBER := 0;
BEGIN
    SELECT COUNT(*) INTO v_total FROM employees;
    DBMS_OUTPUT.PUT_LINE('処理対象: ' || v_total || ' 件');

    FOR rec IN (SELECT employee_id, first_name, last_name FROM employees) LOOP
        -- 何らかの処理
        v_processed := v_processed + 1;
        IF MOD(v_processed, 100) = 0 THEN
            DBMS_OUTPUT.PUT_LINE('  進捗: ' || v_processed || ' / ' || v_total);
        END IF;
    END LOOP;

    DBMS_OUTPUT.PUT_LINE('処理完了: ' || v_processed || ' 件');
END;
/

10.4 ストアドプロシージャ/ファンクションの実行

EXECUTE (EXEC) コマンド

-- プロシージャの実行
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'EMPLOYEES')

-- パラメータ付きプロシージャの実行
SQL> EXEC my_package.update_salary(100, 5000)

-- ファンクションの結果をバインド変数に格納
SQL> VARIABLE result VARCHAR2(100)
SQL> EXEC :result := my_package.get_employee_name(100)
SQL> PRINT result

RESULT
----------------------------------------------------------------------------------------------------
King, Steven

無名ブロックを使用した実行

-- パッケージプロシージャの呼び出し(より複雑なケース)
DECLARE
    v_result VARCHAR2(200);
    v_status NUMBER;
BEGIN
    my_package.process_order(
        p_order_id => 12345,
        p_action   => 'APPROVE',
        p_result   => v_result,
        p_status   => v_status
    );
    DBMS_OUTPUT.PUT_LINE('結果: ' || v_result);
    DBMS_OUTPUT.PUT_LINE('ステータス: ' || v_status);
END;
/

10.5 バインド変数を使った PL/SQL 連携

-- バインド変数の宣言
VARIABLE v_emp_id NUMBER
VARIABLE v_emp_name VARCHAR2(100)
VARIABLE v_salary NUMBER

-- PL/SQL で値を設定
BEGIN
    SELECT employee_id, first_name || ' ' || last_name, salary
    INTO :v_emp_id, :v_emp_name, :v_salary
    FROM employees
    WHERE employee_id = 100;
END;
/

-- バインド変数の値を表示
PRINT v_emp_id
PRINT v_emp_name
PRINT v_salary

-- バインド変数を後続の SQL で使用
SELECT department_id, department_name
FROM departments
WHERE department_id = (
    SELECT department_id FROM employees WHERE employee_id = :v_emp_id
);

10.6 REF CURSOR によるカーソル結果の表示

-- REFCURSORの宣言と使用
VARIABLE rc REFCURSOR

BEGIN
    OPEN :rc FOR
        SELECT d.department_name,
               COUNT(e.employee_id) AS emp_count,
               AVG(e.salary) AS avg_salary
        FROM departments d
        LEFT JOIN employees e ON d.department_id = e.department_id
        GROUP BY d.department_name
        HAVING COUNT(e.employee_id) > 0
        ORDER BY avg_salary DESC;
END;
/

-- カーソル結果の表示(COLUMN設定が適用される)
COLUMN department_name FORMAT A25 HEADING '部門名'
COLUMN emp_count FORMAT 999 HEADING '人数'
COLUMN avg_salary FORMAT $999,999.99 HEADING '平均給与'

PRINT rc

10.7 PL/SQL エラーの確認

-- コンパイルエラーの確認
SQL> SHOW ERRORS

-- 特定のオブジェクトのエラーを確認
SQL> SHOW ERRORS PROCEDURE my_procedure
SQL> SHOW ERRORS PACKAGE BODY my_package
SQL> SHOW ERRORS FUNCTION my_function
SQL> SHOW ERRORS TRIGGER my_trigger

-- エラーの詳細を DBA_ERRORS から確認
SQL> SELECT line, position, text
  2  FROM user_errors
  3  WHERE name = 'MY_PACKAGE'
  4  AND type = 'PACKAGE BODY'
  5  ORDER BY sequence;

10.8 PL/SQL スクリプトの実践例

-- emp_salary_update.sql
-- 給与一括更新スクリプト

SET SERVEROUTPUT ON SIZE UNLIMITED
SET ECHO OFF
SET VERIFY OFF

WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

ACCEPT pct_increase NUMBER PROMPT '昇給率(%)を入力: '
ACCEPT dept_id NUMBER PROMPT '対象部門番号を入力: '

SPOOL /home/oracle/logs/salary_update.log

PROMPT ========================================
PROMPT 給与更新処理開始
PROMPT 対象部門: &dept_id
PROMPT 昇給率:   &pct_increase %
PROMPT ========================================

DECLARE
    v_count NUMBER := 0;
    v_total_increase NUMBER := 0;
    v_pct NUMBER := &pct_increase / 100;
BEGIN
    FOR rec IN (
        SELECT employee_id, first_name, last_name, salary
        FROM employees
        WHERE department_id = &dept_id
        FOR UPDATE
    ) LOOP
        UPDATE employees
        SET salary = salary * (1 + v_pct)
        WHERE employee_id = rec.employee_id;

        v_count := v_count + 1;
        v_total_increase := v_total_increase + (rec.salary * v_pct);

        DBMS_OUTPUT.PUT_LINE(
            RPAD(rec.first_name || ' ' || rec.last_name, 30) ||
            ' : ' || TO_CHAR(rec.salary, '999,999') ||
            ' -> ' || TO_CHAR(rec.salary * (1 + v_pct), '999,999')
        );
    END LOOP;

    DBMS_OUTPUT.PUT_LINE('========================================');
    DBMS_OUTPUT.PUT_LINE('更新件数: ' || v_count || ' 件');
    DBMS_OUTPUT.PUT_LINE('昇給総額: ' || TO_CHAR(v_total_increase, '999,999,999'));
    DBMS_OUTPUT.PUT_LINE('========================================');

    COMMIT;
    DBMS_OUTPUT.PUT_LINE('コミット完了');
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('エラー発生: ' || SQLERRM);
        RAISE;
END;
/

SPOOL OFF
EXIT 0

11. データのインポート/エクスポート

11.1 SPOOL によるデータエクスポート

SQL*Plus の SPOOL 機能を使用して、さまざまな形式でデータをエクスポートできる。

固定幅テキストのエクスポート

SET LINESIZE 200
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON

SPOOL /home/oracle/exports/employees_fixed.txt

SELECT RPAD(employee_id, 6) ||
       RPAD(first_name, 20) ||
       RPAD(last_name, 25) ||
       LPAD(NVL(TO_CHAR(salary), '0'), 10) ||
       RPAD(NVL(TO_CHAR(department_id), ''), 4)
FROM employees
ORDER BY employee_id;

SPOOL OFF

タブ区切り (TSV) のエクスポート

SET LINESIZE 32767
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON
SET COLSEP '	'

SPOOL /home/oracle/exports/employees.tsv

SELECT employee_id, first_name, last_name, salary, department_id
FROM employees
ORDER BY employee_id;

SPOOL OFF

INSERT 文形式のエクスポート

他のデータベースへのデータ移行に便利な形式である。

SET LINESIZE 32767
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON
SET LONG 50000

SPOOL /home/oracle/exports/employees_insert.sql

SELECT 'INSERT INTO employees (employee_id, first_name, last_name, email, salary, department_id) VALUES (' ||
       employee_id || ', ' ||
       '''' || REPLACE(first_name, '''', '''''') || ''', ' ||
       '''' || REPLACE(last_name, '''', '''''') || ''', ' ||
       '''' || email || ''', ' ||
       NVL(TO_CHAR(salary), 'NULL') || ', ' ||
       NVL(TO_CHAR(department_id), 'NULL') || ');'
FROM employees
ORDER BY employee_id;

SELECT 'COMMIT;' FROM dual;

SPOOL OFF

11.2 SQL*Loader との連携

SQLLoader は Oracle Database へのデータロードに特化したユーティリティである。SQLPlus から直接実行はできないが、HOST コマンドや事前準備で連携できる。

制御ファイルの生成(SQL*Plus で作成)

-- SQL*Plusからcontrol fileを生成
SET LINESIZE 200
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON

SPOOL /home/oracle/loader/employees.ctl

SELECT 'LOAD DATA' FROM dual;
SELECT 'INFILE ''/home/oracle/data/employees.csv''' FROM dual;
SELECT 'INTO TABLE hr.employees' FROM dual;
SELECT 'FIELDS TERMINATED BY '','' OPTIONALLY ENCLOSED BY ''"''' FROM dual;
SELECT 'TRAILING NULLCOLS' FROM dual;
SELECT '(' FROM dual;
SELECT '  employee_id INTEGER EXTERNAL,' FROM dual;
SELECT '  first_name CHAR(20),' FROM dual;
SELECT '  last_name CHAR(25),' FROM dual;
SELECT '  email CHAR(25),' FROM dual;
SELECT '  salary DECIMAL EXTERNAL,' FROM dual;
SELECT '  department_id INTEGER EXTERNAL' FROM dual;
SELECT ')' FROM dual;

SPOOL OFF

SQL*Loader の実行(HOST コマンド)

-- SQL*Plus 内から SQL*Loader を実行
SQL> HOST sqlldr userid=hr/password@ORCL control=/home/oracle/loader/employees.ctl log=/home/oracle/loader/employees.log

-- バッチスクリプトからの実行
-- #!/bin/bash
-- sqlldr userid=hr/password@ORCL \
--   control=/home/oracle/loader/employees.ctl \
--   log=/home/oracle/loader/employees.log \
--   bad=/home/oracle/loader/employees.bad \
--   discard=/home/oracle/loader/employees.dsc \
--   direct=true \
--   parallel=true

11.3 外部表(External Tables)の活用

外部表は SQL*Plus から直接 SQL で外部ファイルにアクセスできる機能である。

-- 外部表の作成
CREATE OR REPLACE DIRECTORY ext_data_dir AS '/home/oracle/data';

CREATE TABLE employees_ext (
    employee_id   NUMBER,
    first_name    VARCHAR2(20),
    last_name     VARCHAR2(25),
    email         VARCHAR2(25),
    salary        NUMBER(8,2),
    department_id NUMBER(4)
)
ORGANIZATION EXTERNAL (
    TYPE ORACLE_LOADER
    DEFAULT DIRECTORY ext_data_dir
    ACCESS PARAMETERS (
        RECORDS DELIMITED BY NEWLINE
        FIELDS TERMINATED BY ','
        OPTIONALLY ENCLOSED BY '"'
        MISSING FIELD VALUES ARE NULL
        (
            employee_id,
            first_name,
            last_name,
            email,
            salary,
            department_id
        )
    )
    LOCATION ('employees.csv')
)
REJECT LIMIT UNLIMITED;

-- 外部表からのデータ参照(通常のSQLで可能)
SELECT * FROM employees_ext;

-- 外部表からのデータロード
INSERT INTO employees
SELECT * FROM employees_ext;
COMMIT;

11.4 Data Pump の SQL*Plus からの起動

Data Pump (expdp/impdp) はコマンドラインツールであるが、SQL*Plus から DBMS_DATAPUMP パッケージを通じて実行することもできる。

-- Data Pump エクスポートの PL/SQL 実行
SET SERVEROUTPUT ON SIZE UNLIMITED

DECLARE
    v_handle NUMBER;
    v_status VARCHAR2(100);
BEGIN
    -- Data Pump ジョブの作成
    v_handle := DBMS_DATAPUMP.OPEN(
        operation => 'EXPORT',
        job_mode  => 'SCHEMA',
        job_name  => 'EXP_HR_' || TO_CHAR(SYSDATE, 'YYYYMMDD')
    );

    -- ダンプファイルの設定
    DBMS_DATAPUMP.ADD_FILE(
        handle    => v_handle,
        filename  => 'hr_export_' || TO_CHAR(SYSDATE, 'YYYYMMDD') || '.dmp',
        directory => 'DATA_PUMP_DIR',
        filetype  => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE
    );

    -- ログファイルの設定
    DBMS_DATAPUMP.ADD_FILE(
        handle    => v_handle,
        filename  => 'hr_export_' || TO_CHAR(SYSDATE, 'YYYYMMDD') || '.log',
        directory => 'DATA_PUMP_DIR',
        filetype  => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE
    );

    -- スキーマフィルタ
    DBMS_DATAPUMP.METADATA_FILTER(
        handle => v_handle,
        name   => 'SCHEMA_EXPR',
        value  => 'IN (''HR'')'
    );

    -- ジョブの開始
    DBMS_DATAPUMP.START_JOB(v_handle);

    DBMS_OUTPUT.PUT_LINE('Data Pump エクスポートを開始しました');

    -- ジョブの完了待ち
    DBMS_DATAPUMP.WAIT_FOR_JOB(v_handle, v_status);
    DBMS_OUTPUT.PUT_LINE('ジョブステータス: ' || v_status);
END;
/

11.5 COPY コマンド(レガシー)

COPY コマンドは Oracle データベース間でデータをコピーするための古い SQL*Plus コマンドである。現在は非推奨であるが、一部の環境では依然として使用されている。

-- 別のデータベースからデータをコピー
SQL> COPY FROM scott/tiger@SOURCE_DB -
>    TO scott/tiger@TARGET_DB -
>    INSERT target_table -
>    USING SELECT * FROM source_table;

-- COPY コマンドのオプション
-- INSERT   : ターゲットテーブルにINSERT(テーブルが存在する必要がある)
-- CREATE   : ターゲットテーブルを作成してINSERT
-- REPLACE  : ターゲットテーブルを削除・再作成してINSERT
-- APPEND   : 既存データに追加

-- コミット間隔の設定
SQL> SET COPYCOMMIT 1000
SQL> SET ARRAYSIZE 5000

11.6 DDL スクリプトの生成

DBMS_METADATA パッケージを使用して、テーブルやその他のオブジェクトの DDL を生成できる。

-- DDL 生成の設定
SET LONG 100000
SET LONGCHUNKSIZE 100000
SET LINESIZE 200
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET VERIFY OFF
SET TRIMSPOOL ON

-- テーブルDDLの取得
SPOOL /home/oracle/ddl/employees_ddl.sql

-- DDL変換オプションの設定
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', FALSE);
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'TABLESPACE', FALSE);
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', FALSE);
EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);

SELECT DBMS_METADATA.GET_DDL('TABLE', table_name)
FROM user_tables
ORDER BY table_name;

SPOOL OFF

12. 管理操作

12.1 インスタンスの起動と停止

SQL*Plus は Oracle Database インスタンスの起動・停止を行える唯一の標準ツールである(RMAN やOracle Enterprise Manager も可能)。

STARTUP コマンド

-- 接続(インスタンス起動前)
$ sqlplus / as sysdba
Connected to an idle instance.

-- 完全起動(NOMOUNT → MOUNT → OPEN)
SQL> STARTUP
ORACLE instance started.
Total System Global Area  1073741824 bytes
Fixed Size                    8904448 bytes
Variable Size               645922816 bytes
Database Buffers            411041792 bytes
Redo Buffers                  7872512 bytes
Database mounted.
Database opened.

-- NOMOUNT モードで起動(インスタンスのみ開始、制御ファイル未読込)
SQL> STARTUP NOMOUNT
-- 用途: データベースの作成、制御ファイルの再作成

-- MOUNT モードで起動(制御ファイル読込、データファイル未オープン)
SQL> STARTUP MOUNT
-- 用途: アーカイブログモードの変更、データファイルの名前変更

-- 読み取り専用モードで起動
SQL> STARTUP OPEN READ ONLY

-- 制限モードで起動(DBA権限ユーザーのみアクセス可能)
SQL> STARTUP RESTRICT

-- 特定のパラメータファイルを指定して起動
SQL> STARTUP PFILE='/u01/app/oracle/product/19.0.0/dbs/initORCL.ora'

-- 強制起動(前回の異常終了後など)
SQL> STARTUP FORCE

-- MOUNT → OPEN への遷移
SQL> ALTER DATABASE OPEN;

-- NOMOUNT → MOUNT への遷移
SQL> ALTER DATABASE MOUNT;

SHUTDOWN コマンド

-- 通常の停止(新規接続を拒否し、既存トランザクション完了を待機)
SQL> SHUTDOWN NORMAL

-- トランザクション完了型の停止(未コミットトランザクション完了後に停止)
SQL> SHUTDOWN TRANSACTIONAL

-- 即時停止(未コミットトランザクションをロールバック、推奨)
SQL> SHUTDOWN IMMEDIATE

-- 強制停止(即座にインスタンスを停止、インスタンスリカバリが必要)
SQL> SHUTDOWN ABORT
SHUTDOWN モード新規接続既存セッショントランザクションインスタンスリカバリ
NORMAL拒否待機待機不要
TRANSACTIONAL拒否トランザクション完了後に切断待機不要
IMMEDIATE拒否即座に切断ロールバック不要
ABORT拒否即座に切断未処理必要

12.2 ALTER SYSTEM コマンド

-- メモリパラメータの動的変更
SQL> ALTER SYSTEM SET sga_target = 2G SCOPE=BOTH;
SQL> ALTER SYSTEM SET pga_aggregate_target = 512M SCOPE=BOTH;

-- ログの切り替え
SQL> ALTER SYSTEM SWITCH LOGFILE;

-- アーカイブログの切り替え
SQL> ALTER SYSTEM ARCHIVE LOG CURRENT;

-- チェックポイントの発行
SQL> ALTER SYSTEM CHECKPOINT;

-- 共有プールのフラッシュ
SQL> ALTER SYSTEM FLUSH SHARED_POOL;

-- バッファキャッシュのフラッシュ
SQL> ALTER SYSTEM FLUSH BUFFER_CACHE;

-- セッションの切断
SQL> ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
SQL> ALTER SYSTEM DISCONNECT SESSION 'sid,serial#' POST_TRANSACTION;

-- SCOPE パラメータ
-- MEMORY : メモリ内のみ変更(再起動で元に戻る)
-- SPFILE : SPFILEのみ変更(次回起動時に反映)
-- BOTH   : メモリとSPFILEの両方を変更
SQL> ALTER SYSTEM SET open_cursors = 500 SCOPE=BOTH;

12.3 ALTER SESSION コマンド

-- 日付書式の変更
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

-- タイムスタンプ書式の変更
SQL> ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF3';

-- ソート領域サイズの変更
SQL> ALTER SESSION SET SORT_AREA_SIZE = 10485760;

-- オプティマイザモードの変更
SQL> ALTER SESSION SET OPTIMIZER_MODE = ALL_ROWS;

-- トレースの有効化
SQL> ALTER SESSION SET SQL_TRACE = TRUE;
SQL> ALTER SESSION SET TRACEFILE_IDENTIFIER = 'MY_TRACE';

-- イベントの設定(10046トレース)
SQL> ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 12';

-- パラレル実行の制御
SQL> ALTER SESSION FORCE PARALLEL QUERY PARALLEL 4;
SQL> ALTER SESSION DISABLE PARALLEL QUERY;

-- コンテナの切り替え(マルチテナント環境)
SQL> ALTER SESSION SET CONTAINER = PDB1;

12.4 SHOW コマンドによるパラメータ確認

-- 特定のパラメータを確認
SQL> SHOW PARAMETER sga_target
NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
sga_target                           big integer 2G

-- パターンマッチでパラメータを検索
SQL> SHOW PARAMETER optimizer
NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
optimizer_adaptive_plans             boolean     TRUE
optimizer_adaptive_statistics        boolean     FALSE
optimizer_mode                       string      ALL_ROWS
...

-- すべてのパラメータを表示
SQL> SHOW PARAMETER

-- SGA情報の表示
SQL> SHOW SGA
Total System Global Area 1073741824 bytes
Fixed Size                  8904448 bytes
Variable Size             645922816 bytes
Database Buffers          411041792 bytes
Redo Buffers                7872512 bytes

-- 現在のSPFILE
SQL> SHOW PARAMETER spfile

-- 制御ファイルの場所
SQL> SHOW PARAMETER control_files

-- データベースの情報
SQL> SELECT name, open_mode, log_mode FROM v$database;
SQL> SELECT instance_name, status, database_status FROM v$instance;

12.5 テーブルスペース管理

-- テーブルスペースの作成
CREATE TABLESPACE users_data
  DATAFILE '/u01/oradata/ORCL/users_data01.dbf' SIZE 1G
  AUTOEXTEND ON NEXT 100M MAXSIZE 10G
  EXTENT MANAGEMENT LOCAL
  SEGMENT SPACE MANAGEMENT AUTO;

-- テーブルスペースの使用状況
SELECT tablespace_name,
       ROUND(SUM(bytes)/1024/1024, 2) AS total_mb,
       ROUND(SUM(bytes - NVL(free_bytes, 0))/1024/1024, 2) AS used_mb,
       ROUND(SUM(NVL(free_bytes, 0))/1024/1024, 2) AS free_mb,
       ROUND((SUM(bytes - NVL(free_bytes, 0))/SUM(bytes)) * 100, 2) AS pct_used
FROM (
    SELECT df.tablespace_name,
           df.bytes,
           fs.free_bytes
    FROM dba_data_files df
    LEFT JOIN (
        SELECT tablespace_name, file_id, SUM(bytes) AS free_bytes
        FROM dba_free_space
        GROUP BY tablespace_name, file_id
    ) fs ON df.tablespace_name = fs.tablespace_name AND df.file_id = fs.file_id
)
GROUP BY tablespace_name
ORDER BY pct_used DESC;

-- データファイルの追加
ALTER TABLESPACE users_data
  ADD DATAFILE '/u01/oradata/ORCL/users_data02.dbf' SIZE 1G
  AUTOEXTEND ON NEXT 100M MAXSIZE 10G;

-- テーブルスペースのオフライン/オンライン
ALTER TABLESPACE users_data OFFLINE;
ALTER TABLESPACE users_data ONLINE;

-- テーブルスペースの削除
DROP TABLESPACE temp_data INCLUDING CONTENTS AND DATAFILES;

12.6 ユーザー管理

-- ユーザーの作成
CREATE USER app_user IDENTIFIED BY secure_password
  DEFAULT TABLESPACE users_data
  TEMPORARY TABLESPACE temp
  QUOTA UNLIMITED ON users_data
  PROFILE app_profile;

-- 権限の付与
GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW TO app_user;
GRANT SELECT ON hr.employees TO app_user;
GRANT EXECUTE ON hr.my_package TO app_user;

-- ロールの付与
GRANT CONNECT, RESOURCE TO app_user;

-- ユーザー一覧の確認
SELECT username, account_status, default_tablespace, created
FROM dba_users
WHERE oracle_maintained = 'N'
ORDER BY created DESC;

-- セッション情報の確認
SELECT sid, serial#, username, status, machine, program, logon_time
FROM v$session
WHERE type = 'USER'
ORDER BY logon_time DESC;

13. パフォーマンス分析

13.1 SET AUTOTRACE

AUTOTRACE は SQL*Plus に組み込まれたパフォーマンス分析機能であり、SQL文の実行計画と実行統計を簡易的に確認できる。

事前準備

-- PLAN_TABLE の作成(通常は自動作成済み)
SQL> @$ORACLE_HOME/rdbms/admin/utlxplan.sql

-- PLUSTRACE ロールの作成と付与(SYSDBAとして実行)
SQL> @$ORACLE_HOME/sqlplus/admin/plustrce.sql
SQL> GRANT PLUSTRACE TO scott;

AUTOTRACE の使用

-- 実行計画と統計を表示(クエリ結果も表示)
SQL> SET AUTOTRACE ON
SQL> SELECT employee_id, first_name, salary
  2  FROM employees
  3  WHERE department_id = 10;

EMPLOYEE_ID FIRST_NAME               SALARY
----------- -------------------- ----------
        200 Jennifer                   4400

Execution Plan
----------------------------------------------------------
Plan hash value: 2056577954

------------------------------------------------------------------------------------------
| Id  | Operation                    | Name          | Rows  | Bytes | Cost (%CPU)| Time  |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |               |     1 |    16 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID | EMPLOYEES     |     1 |    16 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN           | EMP_DEPT_IX   |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("DEPARTMENT_ID"=10)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        640  bytes sent via SQL*Net to client
        424  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

-- 実行計画のみ表示
SQL> SET AUTOTRACE ON EXPLAIN

-- 統計のみ表示
SQL> SET AUTOTRACE ON STATISTICS

-- クエリ結果を表示せず、実行計画と統計のみ表示
SQL> SET AUTOTRACE TRACEONLY

-- クエリ結果を表示せず、実行計画のみ表示
SQL> SET AUTOTRACE TRACEONLY EXPLAIN

-- AUTOTRACE を無効化
SQL> SET AUTOTRACE OFF

13.2 EXPLAIN PLAN

EXPLAIN PLAN は SQL 文の実行計画を PLAN_TABLE に保存するコマンドである。

-- 実行計画の取得
EXPLAIN PLAN FOR
SELECT e.employee_id, e.first_name, e.last_name,
       d.department_name, e.salary
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE e.salary > 10000
ORDER BY e.salary DESC;

-- 実行計画の表示(基本)
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

-- 実行計画の表示(詳細情報付き)
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));

-- 実行計画の表示(書式指定)
-- BASIC    : 基本情報のみ
-- TYPICAL  : 標準情報(デフォルト)
-- ALL      : すべての情報
-- SERIAL   : パラレル情報を除外
-- ADVANCED : 内部情報を含むすべての情報
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'TYPICAL'));

13.3 DBMS_XPLAN による実行計画の表示

実際に実行されたSQL文の実行計画(実行後の統計付き)を表示する方法を以下に示す。

-- 実行統計の収集を有効化
ALTER SESSION SET STATISTICS_LEVEL = ALL;

-- SQL文を実行
SELECT e.employee_id, e.first_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE e.salary > 10000;

-- 直前に実行したSQL文の実行計画(実行統計付き)を表示
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));

-- 出力例
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------
SQL_ID  abcde12345, child number 0
-------------------------------------
SELECT e.employee_id, e.first_name, d.department_name ...

Plan hash value: 1234567890

-----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |     14 |00:00:00.01 |      10 |
|*  1 |  HASH JOIN                   |             |      1 |     14 |     14 |00:00:00.01 |      10 |
|   2 |   TABLE ACCESS FULL          | DEPARTMENTS |      1 |     27 |     27 |00:00:00.01 |       6 |
|*  3 |   TABLE ACCESS FULL          | EMPLOYEES   |      1 |     14 |     14 |00:00:00.01 |       4 |
-----------------------------------------------------------------------------------------------------------

-- 特定の SQL_ID の実行計画を表示
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('abcde12345', 0, 'ALLSTATS LAST'));

-- AWR から過去の実行計画を表示
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('abcde12345'));

13.4 SET TIMING ON

SQL文の実行時間を計測する基本的な方法である。

SQL> SET TIMING ON

SQL> SELECT COUNT(*) FROM employees;

  COUNT(*)
----------
       107

Elapsed: 00:00:00.01

SQL> SELECT /*+ FULL(e) */ COUNT(*) FROM employees e;

  COUNT(*)
----------
       107

Elapsed: 00:00:00.02

13.5 TIMING コマンド

複数の処理の実行時間を個別に計測する場合に使用する。

-- タイマーの開始
SQL> TIMING START total_time

SQL> TIMING START query1_time
SQL> SELECT COUNT(*) FROM employees;
SQL> TIMING SHOW query1_time
timing for: query1_time
Elapsed: 00:00:00.01

SQL> TIMING START query2_time
SQL> SELECT COUNT(*) FROM departments;
SQL> TIMING SHOW query2_time
timing for: query2_time
Elapsed: 00:00:00.00

SQL> TIMING STOP total_time
timing for: total_time
Elapsed: 00:00:00.05

13.6 V$SQL による実行統計の確認

-- 特定のSQLの実行統計を確認
COLUMN sql_text FORMAT A60 WORD_WRAPPED
COLUMN elapsed_avg FORMAT 999,999,999

SELECT sql_id,
       executions,
       ROUND(elapsed_time/1000000, 2) AS elapsed_sec,
       ROUND(elapsed_time/GREATEST(executions,1)/1000000, 4) AS elapsed_avg_sec,
       buffer_gets,
       disk_reads,
       rows_processed,
       SUBSTR(sql_text, 1, 60) AS sql_text
FROM v$sql
WHERE sql_text LIKE '%employees%'
AND sql_text NOT LIKE '%v$sql%'
ORDER BY elapsed_time DESC
FETCH FIRST 10 ROWS ONLY;

-- Top SQLの確認(バッファ取得数順)
SELECT sql_id,
       buffer_gets,
       executions,
       ROUND(buffer_gets/GREATEST(executions, 1)) AS gets_per_exec,
       SUBSTR(sql_text, 1, 80) AS sql_text
FROM v$sql
WHERE parsing_schema_name NOT IN ('SYS', 'SYSTEM')
ORDER BY buffer_gets DESC
FETCH FIRST 20 ROWS ONLY;

13.7 tkprof の活用

SQL*Plus から取得したトレースファイルを tkprof で分析する手順を以下に示す。

-- SQL*Plus でトレースを有効化
SQL> ALTER SESSION SET TRACEFILE_IDENTIFIER = 'MY_TRACE_SESSION';
SQL> ALTER SESSION SET SQL_TRACE = TRUE;

-- SQL文の実行
SQL> SELECT * FROM employees WHERE department_id = 10;
SQL> SELECT * FROM departments;

-- トレースの無効化
SQL> ALTER SESSION SET SQL_TRACE = FALSE;

-- トレースファイルの場所を確認
SQL> SELECT value FROM v$diag_info WHERE name = 'Default Trace File';
# tkprof でトレースファイルを分析
tkprof /u01/app/oracle/diag/rdbms/orcl/ORCL/trace/ORCL_ora_12345_MY_TRACE_SESSION.trc \
  /home/oracle/reports/trace_report.txt \
  sort=exeela \
  explain=hr/password@ORCL \
  sys=no \
  waits=yes

13.8 パフォーマンス分析スクリプトの例

-- perf_check.sql
-- 簡易パフォーマンスチェックスクリプト

SET LINESIZE 200
SET PAGESIZE 100
SET FEEDBACK OFF

PROMPT === インスタンス情報 ===
SELECT instance_name, status, TO_CHAR(startup_time, 'YYYY-MM-DD HH24:MI:SS') AS startup
FROM v$instance;

PROMPT === SGA メモリ使用状況 ===
SELECT pool, ROUND(SUM(bytes)/1024/1024, 2) AS mb
FROM v$sgastat
WHERE pool IS NOT NULL
GROUP BY pool
ORDER BY mb DESC;

PROMPT === 待機イベント Top 10 ===
SELECT event, total_waits, ROUND(time_waited_micro/1000000, 2) AS time_waited_sec
FROM v$system_event
WHERE wait_class NOT IN ('Idle')
ORDER BY time_waited_micro DESC
FETCH FIRST 10 ROWS ONLY;

PROMPT === アクティブセッション ===
SELECT COUNT(*) AS active_sessions
FROM v$session
WHERE status = 'ACTIVE'
AND type = 'USER';

14. セキュリティと認証

14.1 認証方式の種類

SQL*Plus で Oracle Database に接続する際の認証方式には、以下の種類がある。

認証方式説明用途
データベース認証ユーザー名とパスワードによる認証一般ユーザー
OS認証OSのユーザーアカウントによる認証DBA(SYSDBA/SYSOPER)
パスワードファイル認証パスワードファイルによるリモート認証リモートDBA
ウォレット認証Oracle Wallet による自動認証自動化スクリプト
プロキシ認証別ユーザーの代理として認証アプリケーション
Kerberos認証Kerberos トークンによる認証エンタープライズ環境
LDAP認証LDAP ディレクトリによる認証統合認証環境

14.2 パスワードの安全な取り扱い

コマンドラインでのパスワード入力を避ける

# 危険: パスワードがプロセスリストやシェル履歴に残る
sqlplus scott/tiger@ORCL                    # 非推奨

# 安全: パスワードの対話的入力
sqlplus scott@ORCL                           # パスワード入力プロンプトが表示される
Enter password: ********

# 安全: /nolog で起動して CONNECT
sqlplus /nolog
SQL> CONNECT scott@ORCL
Enter password: ********

# シェルスクリプトでの安全な方法
sqlplus /nolog <<'EOF'
CONNECT scott@ORCL
-- パスワードは環境変数や設定ファイルから読み取る
EOF

環境変数を使用したパスワード管理

# パスワードを環境変数に設定(ただし完全には安全でない)
export DB_PASSWORD='secure_password'

# スクリプト内でのパスワード参照
sqlplus -S "scott/${DB_PASSWORD}@ORCL" @script.sql

14.3 Oracle Wallet による自動認証

Oracle Wallet を使用すると、パスワードをウォレットファイルに安全に保存し、SQL*Plus からパスワードなしで接続できる。

# ウォレットの作成
mkstore -wrl /opt/oracle/wallet -create
Enter wallet password: ********

# ウォレットに資格情報を追加
mkstore -wrl /opt/oracle/wallet -createCredential ORCL scott tiger
Enter wallet password: ********

# ウォレットの内容確認
mkstore -wrl /opt/oracle/wallet -listCredential
Enter wallet password: ********

sqlnet.ora の設定

# sqlnet.ora
WALLET_LOCATION =
  (SOURCE =
    (METHOD = FILE)
    (METHOD_DATA =
      (DIRECTORY = /opt/oracle/wallet)
    )
  )

SQLNET.WALLET_OVERRIDE = TRUE

ウォレットを使用した接続

# パスワードなしで接続
sqlplus /@ORCL

# スクリプトでの使用(パスワード不要)
sqlplus -S /@ORCL @daily_report.sql

14.4 パスワードファイル認証

リモートからの SYSDBA/SYSOPER 接続にはパスワードファイルが必要である。

# パスワードファイルの作成
orapwd file=$ORACLE_HOME/dbs/orapwORCL password=sys_password entries=10 format=12.2

# パスワードファイルの場所
# Linux:   $ORACLE_HOME/dbs/orapw<SID>
# Windows: $ORACLE_HOME/database/PWD<SID>.ora
-- パスワードファイル認証の有効化
SQL> SHOW PARAMETER remote_login_passwordfile
NAME                                 TYPE        VALUE
------------------------------------ ----------- -----
remote_login_passwordfile            string      EXCLUSIVE

-- SYSDBA/SYSOPER権限の付与
SQL> GRANT SYSDBA TO admin_user;
SQL> GRANT SYSOPER TO oper_user;

-- パスワードファイルに登録されたユーザーの確認
SQL> SELECT * FROM v$pwfile_users;

14.5 プロキシ認証

アプリケーションユーザーが別のスキーマの権限で作業する場合に使用する。

-- プロキシ認証の設定
SQL> ALTER USER hr GRANT CONNECT THROUGH app_user;

-- プロキシ接続
SQL> CONNECT app_user[hr]/app_password@ORCL

-- 現在のユーザーを確認
SQL> SHOW USER
USER is "HR"
SQL> SELECT sys_context('USERENV', 'PROXY_USER') FROM dual;
-- 結果: APP_USER

14.6 監査設定

SQL*Plus からの操作を監査する設定を以下に示す。

-- 統合監査ポリシーの作成
CREATE AUDIT POLICY sensitive_data_policy
  ACTIONS SELECT ON hr.employees,
          UPDATE ON hr.employees,
          DELETE ON hr.employees;

-- 監査ポリシーの有効化
AUDIT POLICY sensitive_data_policy;

-- 特定ユーザーに対する監査
AUDIT POLICY sensitive_data_policy BY scott, app_user;

-- 監査ログの確認
SELECT event_timestamp, dbusername, action_name,
       object_schema, object_name, sql_text
FROM unified_audit_trail
WHERE event_timestamp > SYSDATE - 1
ORDER BY event_timestamp DESC
FETCH FIRST 50 ROWS ONLY;

14.7 機密データのマスキング

SQL*Plus でのデータ表示時に機密情報をマスキングするパターンを以下に示す。

-- クエリレベルでのマスキング
SELECT employee_id,
       first_name,
       last_name,
       REGEXP_REPLACE(email, '(.{2})(.*)(@.*)', '\1****\3') AS email_masked,
       CASE
           WHEN salary IS NOT NULL THEN '***,***'
           ELSE NULL
       END AS salary_masked,
       SUBSTR(phone_number, 1, 3) || '-****-****' AS phone_masked
FROM employees
WHERE department_id = 10;

-- VPD (Virtual Private Database) によるデータマスキング
-- ポリシー関数の作成
CREATE OR REPLACE FUNCTION mask_salary_policy(
    p_schema IN VARCHAR2,
    p_table  IN VARCHAR2
) RETURN VARCHAR2
AS
BEGIN
    IF SYS_CONTEXT('USERENV', 'SESSION_USER') = 'HR_ADMIN' THEN
        RETURN '';  -- HR_ADMIN は全データ閲覧可
    ELSE
        RETURN '1=1';  -- 他ユーザーはフィルタ適用
    END IF;
END;
/

-- Data Redaction によるリアルタイムマスキング
BEGIN
    DBMS_REDACT.ADD_POLICY(
        object_schema  => 'HR',
        object_name    => 'EMPLOYEES',
        column_name    => 'SALARY',
        policy_name    => 'MASK_SALARY',
        function_type  => DBMS_REDACT.FULL,
        expression     => 'SYS_CONTEXT(''USERENV'',''SESSION_USER'') != ''HR'''
    );
END;
/

15. SQL*Plus のカスタマイズ

15.1 login.sql のベストプラクティス

login.sql は SQL*Plus の起動時に自動的に実行される個人設定ファイルであり、作業効率を大幅に向上させることができる。

推奨 login.sql テンプレート

-- ================================================================
-- login.sql - SQL*Plus カスタマイズ設定
-- 配置場所: $SQLPATH/login.sql または カレントディレクトリ
-- ================================================================

-- === 基本表示設定 ===
SET LINESIZE 300
SET PAGESIZE 100
SET LONG 50000
SET LONGCHUNKSIZE 50000

-- === 出力制御 ===
SET TRIMSPOOL ON
SET TRIMOUT ON
SET WRAP ON
SET TAB OFF
SET NULL '(null)'

-- === フィードバック制御 ===
SET FEEDBACK ON
SET VERIFY OFF
SET ECHO OFF

-- === 実行時間表示 ===
SET TIMING ON

-- === PL/SQL出力 ===
SET SERVEROUTPUT ON SIZE UNLIMITED FORMAT WORD_WRAPPED

-- === エディタ設定 ===
DEFINE _EDITOR = vi
-- DEFINE _EDITOR = "code --wait"    -- VS Code 使用時
-- DEFINE _EDITOR = nano             -- nano 使用時

-- === 日付書式 ===
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF3';

-- === カスタムプロンプト ===
-- ユーザー名@接続先 + 日時 をプロンプトに表示
SET SQLPROMPT "_USER'@'_CONNECT_IDENTIFIER _DATE> "

-- === 頻出カラム書式 ===
COLUMN owner FORMAT A25
COLUMN table_name FORMAT A30
COLUMN column_name FORMAT A30
COLUMN object_name FORMAT A35
COLUMN object_type FORMAT A20
COLUMN status FORMAT A10
COLUMN tablespace_name FORMAT A25
COLUMN username FORMAT A25
COLUMN segment_name FORMAT A30
COLUMN index_name FORMAT A30

-- === 起動メッセージ ===
PROMPT
PROMPT ==========================================
PROMPT   SQL*Plus カスタム環境 ロード完了
PROMPT   ユーザー: _USER
PROMPT   接続先:   _CONNECT_IDENTIFIER
PROMPT ==========================================
PROMPT

15.2 glogin.sql のカスタマイズ

glogin.sql は全ユーザーに適用されるため、組織全体の標準設定を定義するのに適している。

-- ================================================================
-- glogin.sql - 全社共通 SQL*Plus 設定
-- 配置場所: $ORACLE_HOME/sqlplus/admin/glogin.sql
-- ================================================================

-- === 基本設定 ===
SET LINESIZE 200
SET PAGESIZE 50

-- === セキュリティ設定 ===
SET VERIFY OFF

-- === 環境識別用プロンプト ===
-- 本番環境を明示するプロンプト設定
COLUMN con_name NEW_VALUE v_con_name NOPRINT
SELECT SYS_CONTEXT('USERENV', 'CON_NAME') AS con_name FROM dual;

COLUMN instance NEW_VALUE v_instance NOPRINT
SELECT UPPER(instance_name) AS instance FROM v$instance;

-- 本番環境の場合は警告表示
SET SQLPROMPT "_USER'@'&v_instance.(&v_con_name.)> "

-- 本番環境検出
COLUMN env_warning NEW_VALUE v_env NOPRINT
SELECT CASE
    WHEN UPPER(instance_name) LIKE '%PROD%' THEN '*** 本番環境 ***'
    WHEN UPPER(instance_name) LIKE '%PRD%'  THEN '*** 本番環境 ***'
    ELSE ''
END AS env_warning
FROM v$instance;

PROMPT &v_env

15.3 SET SQLPROMPT によるプロンプトのカスタマイズ

SQL*Plus のプロンプトを動的にカスタマイズできる。

-- デフォルトプロンプト
SQL> SET SQLPROMPT "SQL> "

-- ユーザー名を表示
SQL> SET SQLPROMPT "_USER> "
SCOTT>

-- ユーザー名と接続先を表示
SQL> SET SQLPROMPT "_USER'@'_CONNECT_IDENTIFIER> "
SCOTT@ORCL>

-- 日付を含むプロンプト
SQL> SET SQLPROMPT "_USER'@'_CONNECT_IDENTIFIER _DATE> "
SCOTT@ORCL 13-APR-26>

-- 権限情報を含むプロンプト
SQL> SET SQLPROMPT "_USER _PRIVILEGE'@'_CONNECT_IDENTIFIER> "
SYS AS SYSDBA@ORCL>

-- 利用可能な事前定義変数
-- _USER              : 現在のユーザー名
-- _CONNECT_IDENTIFIER: 接続識別子
-- _DATE              : 現在の日付
-- _PRIVILEGE          : 接続権限(AS SYSDBA 等)
-- _SQLPLUS_RELEASE    : SQL*Plus のバージョン
-- _EDITOR             : 設定されたエディタ
-- _O_VERSION          : Oracle Database のバージョン
-- _O_RELEASE          : Oracle Database のリリース番号

15.4 エディタの設定

-- デフォルトエディタの設定
SQL> DEFINE _EDITOR = vi

-- 各エディタの設定例
SQL> DEFINE _EDITOR = vim
SQL> DEFINE _EDITOR = nano
SQL> DEFINE _EDITOR = emacs
SQL> DEFINE _EDITOR = "code --wait"          -- VS Code
SQL> DEFINE _EDITOR = "subl --wait"          -- Sublime Text
SQL> DEFINE _EDITOR = notepad                -- Windows メモ帳

-- エディタの使用
SQL> EDIT                      -- バッファ内容をエディタで開く
SQL> EDIT /path/to/script.sql  -- 指定ファイルをエディタで開く

-- エディタの一時ファイルの場所
-- Linux: /tmp/afiedt.buf (デフォルト)
-- SET EDITFILE を使用して変更可能
SQL> SET EDITFILE /home/oracle/tmp/sqlplus_edit.sql

15.5 カスタムヘルパースクリプト

よく使う操作をスクリプト化しておくと効率的である。

-- === desc_full.sql: テーブルの詳細情報を表示 ===
-- 使用方法: @desc_full <テーブル名>
SET VERIFY OFF
PROMPT
PROMPT === テーブル情報: &1 ===
SELECT table_name, tablespace_name, num_rows, avg_row_len, last_analyzed
FROM user_tables WHERE table_name = UPPER('&1');

PROMPT === カラム情報 ===
SELECT column_name, data_type, data_length, nullable, data_default
FROM user_tab_columns WHERE table_name = UPPER('&1')
ORDER BY column_id;

PROMPT === インデックス情報 ===
SELECT index_name, index_type, uniqueness, status
FROM user_indexes WHERE table_name = UPPER('&1');

PROMPT === 制約情報 ===
SELECT constraint_name, constraint_type, status, search_condition
FROM user_constraints WHERE table_name = UPPER('&1');
SET VERIFY ON

-- === session_info.sql: 現在のセッション情報を表示 ===
SELECT SYS_CONTEXT('USERENV', 'SESSION_USER') AS "ユーザー",
       SYS_CONTEXT('USERENV', 'DB_NAME') AS "DB名",
       SYS_CONTEXT('USERENV', 'INSTANCE_NAME') AS "インスタンス",
       SYS_CONTEXT('USERENV', 'SERVICE_NAME') AS "サービス名",
       SYS_CONTEXT('USERENV', 'HOST') AS "クライアントホスト",
       SYS_CONTEXT('USERENV', 'IP_ADDRESS') AS "IPアドレス",
       SYS_CONTEXT('USERENV', 'SID') AS "SID",
       SYS_CONTEXT('USERENV', 'CON_NAME') AS "コンテナ名"
FROM dual;

-- === locks.sql: ロック待ちの確認 ===
SELECT l.sid, l.type, l.lmode, l.request, l.block,
       s.username, s.program, s.machine,
       o.object_name, o.object_type
FROM v$lock l
JOIN v$session s ON l.sid = s.sid
LEFT JOIN dba_objects o ON l.id1 = o.object_id
WHERE l.block = 1 OR l.request > 0
ORDER BY l.block DESC, l.sid;

15.6 環境別の設定管理

# 環境ごとに異なるlogin.sqlを使い分ける

# 開発環境用
export SQLPATH=/home/oracle/sqlplus/dev
# dev/login.sql に開発環境向け設定を配置

# 本番環境用
export SQLPATH=/home/oracle/sqlplus/prod
# prod/login.sql に本番環境向け設定を配置

# シェルのエイリアスを活用
alias sqlplus_dev='SQLPATH=/home/oracle/sqlplus/dev sqlplus'
alias sqlplus_prod='SQLPATH=/home/oracle/sqlplus/prod sqlplus'

16. エラーハンドリング

16.1 WHENEVER SQLERROR の詳細

WHENEVER SQLERROR は SQL エラー発生時の動作を制御する最も重要なコマンドである。

-- エラー発生時にスクリプトを終了(ロールバック)
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

-- エラー発生時にスクリプトを終了(コミット)
WHENEVER SQLERROR EXIT SQL.SQLCODE COMMIT

-- エラー発生時に固定の終了コードで終了
WHENEVER SQLERROR EXIT 1 ROLLBACK

-- エラーを無視して処理を継続
WHENEVER SQLERROR CONTINUE

-- エラーメッセージを表示しない
WHENEVER SQLERROR CONTINUE NONE

エラーハンドリングの使い分けパターン

-- パターン1: 厳格なエラーハンドリング(推奨)
-- すべてのエラーでスクリプトを停止する
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

CREATE TABLE new_table (id NUMBER PRIMARY KEY);
INSERT INTO new_table VALUES (1);
INSERT INTO new_table VALUES (2);
COMMIT;

-- パターン2: 選択的エラーハンドリング
-- 一部のエラーを許容する
WHENEVER SQLERROR CONTINUE
DROP TABLE temp_table;              -- テーブルが存在しなくてもOK
DROP INDEX temp_index;              -- インデックスが存在しなくてもOK

WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
CREATE TABLE temp_table (id NUMBER);
CREATE INDEX temp_index ON temp_table(id);
INSERT INTO temp_table VALUES (1);
COMMIT;

-- パターン3: 段階的エラーハンドリング
-- 準備フェーズではエラーを許容、実行フェーズでは厳格に
PROMPT === 準備フェーズ(エラー許容)===
WHENEVER SQLERROR CONTINUE
DROP TABLE staging_table;
DROP TABLE result_table;

PROMPT === 実行フェーズ(エラー厳格)===
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
CREATE TABLE staging_table AS SELECT * FROM source_table WHERE 1=0;
CREATE TABLE result_table AS SELECT * FROM source_table WHERE 1=0;
-- 以降のエラーはスクリプト停止

16.2 WHENEVER OSERROR

OS レベルのエラー(HOST コマンド失敗、ファイルアクセスエラーなど)発生時の動作を制御する。

-- OSエラー発生時にスクリプトを終了
WHENEVER OSERROR EXIT 9 ROLLBACK

-- OSエラーを無視して継続
WHENEVER OSERROR CONTINUE

-- 使用例
WHENEVER OSERROR EXIT 9
HOST mkdir -p /home/oracle/exports/$(date +%Y%m%d)

WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
SPOOL /home/oracle/exports/$(date +%Y%m%d)/data.csv
SELECT * FROM employees;
SPOOL OFF

16.3 SQL.SQLCODE

SQL.SQLCODE は直前に実行された SQL文の戻りコードを保持する変数である。

-- SQL.SQLCODE の値
-- 0     : 正常終了
-- 正の値 : Oracle エラーコード(ORA-xxxxx の xxxxx 部分)

-- EXIT で SQL.SQLCODE を使用
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

-- シェルスクリプトでの戻り値チェック
-- #!/bin/bash
-- sqlplus -S scott/tiger@ORCL @script.sql
-- RC=$?
-- echo "SQL*Plus 終了コード: ${RC}"

16.4 堅牢なスクリプトテンプレート

-- ================================================================
-- robust_script_template.sql
-- 堅牢なバッチスクリプトテンプレート
-- ================================================================

-- === 環境設定 ===
SET ECHO OFF
SET VERIFY OFF
SET FEEDBACK ON
SET HEADING ON
SET LINESIZE 200
SET PAGESIZE 100
SET SERVEROUTPUT ON SIZE UNLIMITED
SET TIMING ON

-- === ログ設定 ===
DEFINE log_file = '/var/log/oracle/batch/script_&_DATE..log'
SPOOL &log_file

PROMPT ================================================================
PROMPT スクリプト開始: &_DATE
PROMPT 実行ユーザー:   &_USER
PROMPT 接続先:         &_CONNECT_IDENTIFIER
PROMPT ================================================================

-- === エラーハンドリング ===
WHENEVER OSERROR EXIT 9 ROLLBACK
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

-- === 前提条件チェック ===
DECLARE
    v_count NUMBER;
BEGIN
    -- テーブルの存在確認
    SELECT COUNT(*) INTO v_count
    FROM user_tables
    WHERE table_name = 'TARGET_TABLE';

    IF v_count = 0 THEN
        RAISE_APPLICATION_ERROR(-20001, 'TARGET_TABLE が存在しません');
    END IF;

    -- 権限チェック
    SELECT COUNT(*) INTO v_count
    FROM user_tab_privs
    WHERE table_name = 'TARGET_TABLE'
    AND privilege = 'INSERT';

    DBMS_OUTPUT.PUT_LINE('前提条件チェック: OK');
END;
/

-- === メイン処理 ===
PROMPT メイン処理を開始します...

BEGIN
    -- 処理ロジック
    INSERT INTO target_table
    SELECT * FROM source_table
    WHERE created_date = TRUNC(SYSDATE - 1);

    DBMS_OUTPUT.PUT_LINE('挿入件数: ' || SQL%ROWCOUNT);
    COMMIT;
    DBMS_OUTPUT.PUT_LINE('コミット完了');
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('エラー発生: ' || SQLERRM);
        DBMS_OUTPUT.PUT_LINE('エラーコード: ' || SQLCODE);
        RAISE;
END;
/

-- === 後処理 ===
PROMPT 後処理を実行します...

-- 統計情報の収集
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'TARGET_TABLE');

PROMPT ================================================================
PROMPT スクリプト完了: &_DATE
PROMPT ================================================================

SPOOL OFF
EXIT 0

16.5 エラーログ記録パターン

-- エラーログテーブルの作成
CREATE TABLE script_error_log (
    log_id        NUMBER GENERATED ALWAYS AS IDENTITY,
    script_name   VARCHAR2(200),
    error_code    NUMBER,
    error_message VARCHAR2(4000),
    error_time    TIMESTAMP DEFAULT SYSTIMESTAMP,
    username      VARCHAR2(30) DEFAULT USER
);

-- エラーログ記録プロシージャ
CREATE OR REPLACE PROCEDURE log_error(
    p_script  IN VARCHAR2,
    p_code    IN NUMBER,
    p_message IN VARCHAR2
) AS
    PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
    INSERT INTO script_error_log (script_name, error_code, error_message)
    VALUES (p_script, p_code, p_message);
    COMMIT;
END;
/

-- スクリプトでの使用例
SET SERVEROUTPUT ON
DECLARE
    v_count NUMBER;
BEGIN
    -- メイン処理
    INSERT INTO target_table SELECT * FROM source_table;
    v_count := SQL%ROWCOUNT;
    COMMIT;
    DBMS_OUTPUT.PUT_LINE('処理完了: ' || v_count || '件');
EXCEPTION
    WHEN OTHERS THEN
        log_error('daily_batch.sql', SQLCODE, SQLERRM);
        ROLLBACK;
        RAISE;
END;
/

16.6 よくあるエラーと対処法

エラーコードメッセージ原因対処
ORA-00942table or view does not existテーブルが存在しないスキーマ名の確認、権限の確認
ORA-01017invalid username/password認証失敗ユーザー名/パスワードの確認
ORA-12154TNS:could not resolve the connect identifierTNS名前解決失敗tnsnames.ora の確認
ORA-12541TNS:no listenerリスナー未起動lsnrctl status で確認
ORA-01031insufficient privileges権限不足必要な権限を付与
ORA-00054resource busyロック競合ロック保持セッションの確認
ORA-01555snapshot too oldUNDO不足UNDO表領域の拡張
SP2-0310unable to open fileファイルが見つからないパスの確認
SP2-0734unknown commandSQL*Plusコマンドのタイプミスコマンド名の確認

17. マルチテナント環境での SQL*Plus

17.1 マルチテナントアーキテクチャの概要

Oracle 12c で導入されたマルチテナントアーキテクチャでは、1つのコンテナデータベース (CDB) 内に複数のプラガブルデータベース (PDB) を格納できる。SQL*Plus ではこれらのコンテナ間を切り替えて操作する。

┌─────────────────────────────────────────────┐
│                    CDB (コンテナDB)            │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  CDB$ROOT │  │  PDB$SEED │  │   PDB1   │   │
│  │ (ルート)   │  │ (テンプレ) │  │          │   │
│  └──────────┘  └──────────┘  └──────────┘   │
│                               ┌──────────┐   │
│                               │   PDB2   │   │
│                               │          │   │
│                               └──────────┘   │
└─────────────────────────────────────────────┘

17.2 CDB/PDB への接続

-- CDB のルートコンテナに接続
sqlplus / as sysdba
-- デフォルトで CDB$ROOT に接続される

-- 特定の PDB にサービス名で直接接続
sqlplus hr/password@dbserver:1521/pdb1.example.com

-- tnsnames.ora を使用した PDB 接続
-- PDB1 =
--   (DESCRIPTION =
--     (ADDRESS = (PROTOCOL = TCP)(HOST = dbserver)(PORT = 1521))
--     (CONNECT_DATA = (SERVICE_NAME = pdb1.example.com))
--   )
sqlplus hr/password@PDB1

17.3 コンテナの切り替え

-- 現在のコンテナを確認
SQL> SHOW CON_NAME
CON_NAME
------------------------------
CDB$ROOT

SQL> SHOW CON_ID
CON_ID
------------------------------
1

-- PDB に切り替え
SQL> ALTER SESSION SET CONTAINER = PDB1;
Session altered.

SQL> SHOW CON_NAME
CON_NAME
------------------------------
PDB1

-- ルートコンテナに戻る
SQL> ALTER SESSION SET CONTAINER = CDB$ROOT;

-- すべてのPDBの一覧表示
SQL> SELECT con_id, name, open_mode, restricted FROM v$pdbs;

    CON_ID NAME                           OPEN_MODE  RES
---------- ------------------------------ ---------- ---
         2 PDB$SEED                       READ ONLY  NO
         3 PDB1                           READ WRITE NO
         4 PDB2                           READ WRITE NO

17.4 PDB の管理操作

-- PDB のオープン
SQL> ALTER PLUGGABLE DATABASE PDB1 OPEN;

-- PDB のクローズ
SQL> ALTER PLUGGABLE DATABASE PDB1 CLOSE IMMEDIATE;

-- すべての PDB をオープン
SQL> ALTER PLUGGABLE DATABASE ALL OPEN;

-- PDB を読み取り専用でオープン
SQL> ALTER PLUGGABLE DATABASE PDB1 OPEN READ ONLY;

-- PDB の保存状態を設定(CDB再起動時に自動オープン)
SQL> ALTER PLUGGABLE DATABASE PDB1 SAVE STATE;

-- PDB の作成
SQL> CREATE PLUGGABLE DATABASE pdb3
  2  ADMIN USER pdb3_admin IDENTIFIED BY password
  3  FILE_NAME_CONVERT = ('/u01/oradata/CDB/pdbseed/', '/u01/oradata/CDB/pdb3/')
  4  STORAGE (MAXSIZE 10G)
  5  DEFAULT TABLESPACE users
  6  DATAFILE '/u01/oradata/CDB/pdb3/users01.dbf' SIZE 500M AUTOEXTEND ON;

-- PDB のクローン
SQL> CREATE PLUGGABLE DATABASE pdb3_clone FROM pdb1
  2  FILE_NAME_CONVERT = ('/u01/oradata/CDB/pdb1/', '/u01/oradata/CDB/pdb3_clone/');

-- PDB のドロップ
SQL> ALTER PLUGGABLE DATABASE pdb3 CLOSE IMMEDIATE;
SQL> DROP PLUGGABLE DATABASE pdb3 INCLUDING DATAFILES;

17.5 共通ユーザーとローカルユーザー

-- 共通ユーザーの作成(CDB全体で有効、C## プレフィックス必須)
SQL> ALTER SESSION SET CONTAINER = CDB$ROOT;
SQL> CREATE USER c##admin IDENTIFIED BY password
  2  CONTAINER = ALL;

-- 共通ユーザーに権限を付与
SQL> GRANT CREATE SESSION, DBA TO c##admin CONTAINER = ALL;

-- ローカルユーザーの作成(特定のPDB内でのみ有効)
SQL> ALTER SESSION SET CONTAINER = PDB1;
SQL> CREATE USER local_user IDENTIFIED BY password
  2  DEFAULT TABLESPACE users;
SQL> GRANT CREATE SESSION, CREATE TABLE TO local_user;

-- 共通ロールの作成
SQL> ALTER SESSION SET CONTAINER = CDB$ROOT;
SQL> CREATE ROLE c##app_role CONTAINER = ALL;
SQL> GRANT SELECT ANY TABLE TO c##app_role CONTAINER = ALL;

17.6 マルチテナント環境でのスクリプト実行

-- 複数PDBに対して同じSQLを実行
-- CDB$ROOT から全PDBに対してDDLを実行
SQL> ALTER SESSION SET CONTAINER = CDB$ROOT;

-- PDB1 での実行
SQL> ALTER SESSION SET CONTAINER = PDB1;
SQL> @/home/oracle/scripts/create_tables.sql
SQL> ALTER SESSION SET CONTAINER = CDB$ROOT;

-- PDB2 での実行
SQL> ALTER SESSION SET CONTAINER = PDB2;
SQL> @/home/oracle/scripts/create_tables.sql
SQL> ALTER SESSION SET CONTAINER = CDB$ROOT;

シェルスクリプトによるマルチPDB処理

#!/bin/bash
# multi_pdb_execute.sh - 複数PDBに対してSQLスクリプトを実行

SCRIPT=$1
LOG_DIR=/var/log/oracle/multi_pdb

# PDB一覧の取得
PDBS=$(sqlplus -S / as sysdba <<'EOF'
SET HEADING OFF FEEDBACK OFF PAGESIZE 0
SELECT name FROM v$pdbs WHERE name NOT IN ('PDB$SEED') AND open_mode = 'READ WRITE';
EXIT;
EOF
)

for PDB in ${PDBS}; do
    echo "=== PDB: ${PDB} ==="
    sqlplus -S / as sysdba <<EOF > ${LOG_DIR}/${PDB}_$(date +%Y%m%d).log 2>&1
ALTER SESSION SET CONTAINER = ${PDB};
@${SCRIPT}
EXIT;
EOF
    RC=$?
    if [ ${RC} -ne 0 ]; then
        echo "ERROR: PDB ${PDB} でスクリプト実行に失敗しました (RC=${RC})"
    else
        echo "OK: PDB ${PDB} でスクリプト実行が完了しました"
    fi
done

17.7 CDB/PDB のモニタリング

-- PDB のリソース使用状況
SELECT con_id, pdb_name,
       ROUND(SUM(bytes)/1024/1024/1024, 2) AS size_gb
FROM cdb_data_files
GROUP BY con_id, pdb_name
ORDER BY con_id;

-- PDB ごとのセッション数
SELECT con_id, COUNT(*) AS session_count
FROM v$session
WHERE type = 'USER'
GROUP BY con_id
ORDER BY con_id;

-- PDB の SGA 使用状況(Oracle 19c以降)
SELECT con_id, pdb_name,
       ROUND(sga_target/1024/1024) AS sga_target_mb,
       ROUND(sga_actual/1024/1024) AS sga_actual_mb
FROM v$pdbs;

18. SQL*Plus vs 代替ツール

18.1 ツール比較概要

Oracle Database に接続できるクライアントツールは複数存在する。以下に主要ツールの特徴を比較する。

特徴SQL*PlusSQLclSQL DeveloperDBeaverpsql (参考)
提供元OracleOracleOracleOSSPostgreSQL
UICLICLIGUIGUICLI
Java必要不要必要必要必要不要
インストールサイズ
スクリプト機能標準拡張基本基本標準
SQL*Plus互換-部分的なしなし
コマンド履歴限定的ありありありあり
タブ補完なしありありありあり
構文ハイライトなしありありありなし
マルチDB対応OracleOracle多数多数PostgreSQL
自動化適性
ライセンスOracle付属無料無料OSSOSS

18.2 SQLcl (SQL Developer Command Line)

SQLcl は Oracle が提供する次世代コマンドラインツールであり、SQL*Plus の上位互換として位置づけられる。

# SQLcl の起動
$ sql scott/tiger@ORCL

# SQL*Plus と同じコマンドがそのまま使用可能
SQL> SET LINESIZE 200
SQL> SET PAGESIZE 50
SQL> SELECT * FROM employees WHERE rownum <= 5;

SQLcl の固有機能

-- コマンド履歴(上下矢印キーで操作可能)
SQL> HISTORY
SQL> HISTORY FULL

-- タブ補完
SQL> SELECT emp<TAB>
-- employee_id, employees, ... が補完候補として表示される

-- インラインエディタ
SQL> EDIT INLINE

-- JSON 出力
SQL> SET SQLFORMAT JSON
SQL> SELECT * FROM employees WHERE rownum <= 3;

-- CSV 出力
SQL> SET SQLFORMAT CSV
SQL> SELECT * FROM employees;

-- INSERT 文形式の出力
SQL> SET SQLFORMAT INSERT
SQL> SELECT * FROM employees WHERE rownum <= 3;

-- 出力形式の一覧
-- ANSICONSOLE : ターミナル幅に合わせた表形式
-- CSV         : カンマ区切り
-- HTML        : HTML テーブル
-- INSERT      : INSERT 文
-- JSON        : JSON 形式
-- LOADER      : SQL*Loader 用
-- XML         : XML 形式
-- FIXED       : 固定幅
-- DEFAULT     : SQL*Plus 互換

-- Liquibase 統合
SQL> LB GENERATE-SCHEMA -grants -split

-- DATAPUMP API 統合
SQL> DATAPUMP EXPORT -schemas HR -directory DATA_PUMP_DIR

-- SODA (Simple Oracle Document Access) 対応
SQL> SODA CREATE emp_collection
SQL> SODA INSERT emp_collection {"name": "John", "age": 30}
SQL> SODA GET emp_collection

18.3 SQL Developer

SQL Developer は Oracle が提供するフリーの GUI 開発ツールである。

SQL Developer の主な利点

  • ビジュアルなクエリビルダー: ドラッグ&ドロップでSQLを構築
  • データのグリッド表示: スプレッドシート形式でのデータ閲覧・編集
  • PL/SQLデバッガー: ステップ実行、ブレークポイント設定
  • ER図の自動生成: テーブル関連の視覚化
  • DBA機能: ストレージ管理、セッション管理のGUI
  • データモデリング: 論理/物理データモデルの設計
  • バージョン管理統合: Git、SVN との連携
  • レポート機能: カスタムレポートの作成

SQL*Plus との使い分け

SQL Developer を使うべき場面:
  - 対話的なデータ探索
  - PL/SQL の開発・デバッグ
  - ER 図やデータモデルの確認
  - 複雑なクエリの構築

SQL*Plus を使うべき場面:
  - バッチ処理・自動化スクリプト
  - CI/CD パイプラインでの SQL 実行
  - SSH 経由のリモートサーバー操作
  - データベースの起動・停止
  - 緊急時のトラブルシューティング
  - 軽量で高速な接続が必要な場面

18.4 DBeaver

DBeaver は Java ベースのオープンソースデータベースクライアントであり、100種類以上のデータベースに対応している。

DBeaver の主な利点

  • マルチデータベース対応: Oracle、PostgreSQL、MySQL、SQL Server、MongoDB 等
  • ERD 自動生成: テーブル関連図の自動描画
  • データ編集: GUI でのデータ直接編集
  • クエリ結果の可視化: チャート、グラフ機能
  • プラグインエコシステム: 拡張機能の追加

DBeaver の制限事項

  • SQL*Plus コマンド(SET、COLUMN、SPOOL 等)は使用不可
  • データベースの STARTUP/SHUTDOWN は不可
  • 大量のスクリプト自動化には不向き

18.5 psql との比較(PostgreSQL ユーザー向け)

PostgreSQL の psql と SQL*Plus は思想が似ているが、コマンド体系が異なる。

操作SQL*Pluspsql
接続sqlplus user/pass@dbpsql -U user -d db
テーブル一覧SELECT * FROM user_tables;\dt
テーブル構造DESC table_name\d table_name
出力をファイルにSPOOL file.txt\o file.txt
スクリプト実行@script.sql\i script.sql
変数定義DEFINE var = value\set var value
表示設定SET LINESIZE 200\pset columns 200
タイミングSET TIMING ON\timing on
エディタ起動EDIT\e
ヘルプHELP\?
終了EXIT\q
実行計画SET AUTOTRACE ONEXPLAIN ANALYZE
NULL 表示SET NULL '(null)'\pset null '(null)'

18.6 ツール選択のガイドライン

1. 初心者 / GUI 好み      → SQL Developer
2. マルチDB環境           → DBeaver
3. バッチ処理 / 自動化     → SQL*Plus
4. モダンCLI              → SQLcl
5. CI/CD パイプライン      → SQL*Plus (Instant Client)
6. PL/SQL 開発            → SQL Developer + SQL*Plus
7. DBA 管理作業           → SQL*Plus (必須) + SQL Developer (補助)
8. PostgreSQL 移行者       → SQLcl (psql に近い操作感)

19. 高度なスクリプティングパターン

19.1 動的SQL生成パターン(Spool-and-Execute)

SQL*Plus で最も強力なパターンの一つが「スプール生成パターン(Spool-and-Execute)」である。SQLクエリの結果として別のSQL文を生成し、それを実行する手法である。

-- パターン: 全テーブルの統計情報を収集するスクリプトを動的生成
SET LINESIZE 200
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET VERIFY OFF
SET TRIMSPOOL ON
SET TERMOUT OFF

SPOOL /tmp/gather_stats.sql

SELECT 'EXEC DBMS_STATS.GATHER_TABLE_STATS(''' || owner || ''', ''' || table_name || ''');'
FROM all_tables
WHERE owner = 'HR'
AND last_analyzed < SYSDATE - 7
ORDER BY table_name;

SELECT 'EXIT 0;' FROM dual;

SPOOL OFF
SET TERMOUT ON

-- 生成されたスクリプトを実行
@/tmp/gather_stats.sql

インデックス再構築の動的生成

-- 断片化したインデックスの再構築スクリプトを生成
SET LINESIZE 200
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON

SPOOL /tmp/rebuild_indexes.sql

SELECT 'ALTER INDEX ' || owner || '.' || index_name || ' REBUILD ONLINE;'
FROM dba_indexes
WHERE status = 'UNUSABLE'
OR (blevel > 4)
ORDER BY owner, index_name;

SPOOL OFF

-- 実行
WHENEVER SQLERROR CONTINUE
@/tmp/rebuild_indexes.sql

19.2 メタデータ駆動スクリプト

データベースのメタデータを元にDDL文やDML文を自動生成するパターンである。

-- パターン: すべてのテーブルの行数を一括で取得
SET LINESIZE 200
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON

SPOOL /tmp/count_all_tables.sql

SELECT 'PROMPT Table: ' || table_name || ';' || CHR(10) ||
       'SELECT ''' || table_name || ''', COUNT(*) FROM ' || table_name || ';'
FROM user_tables
ORDER BY table_name;

SPOOL OFF

SET HEADING ON
SET FEEDBACK ON
SET PAGESIZE 50

@/tmp/count_all_tables.sql

権限付与の自動生成

-- 特定のロールに全テーブルの SELECT 権限を付与
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON

SPOOL /tmp/grant_select.sql

SELECT 'GRANT SELECT ON ' || owner || '.' || table_name || ' TO app_readonly;'
FROM dba_tables
WHERE owner = 'HR'
ORDER BY table_name;

SPOOL OFF

WHENEVER SQLERROR CONTINUE
@/tmp/grant_select.sql

19.3 マルチステップデプロイメントスクリプト

大規模なデータベース変更を段階的に適用するスクリプトパターンである。

-- ================================================================
-- deploy_v2.0.sql - バージョン2.0 デプロイスクリプト
-- ================================================================

SET ECHO ON
SET TIMING ON
SET SERVEROUTPUT ON SIZE UNLIMITED

WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK
WHENEVER OSERROR EXIT 9 ROLLBACK

SPOOL /var/log/oracle/deploy/deploy_v2.0_&_DATE..log

PROMPT ================================================================
PROMPT デプロイメント v2.0 開始
PROMPT 日時: &_DATE
PROMPT ================================================================

-- Step 1: 前提条件チェック
PROMPT === Step 1: 前提条件チェック ===
DECLARE
    v_version VARCHAR2(20);
BEGIN
    SELECT version INTO v_version
    FROM schema_version
    WHERE schema_name = 'APP'
    AND is_current = 'Y';

    IF v_version != '1.9' THEN
        RAISE_APPLICATION_ERROR(-20001,
            '前提バージョンが不一致です。期待: 1.9, 実際: ' || v_version);
    END IF;
    DBMS_OUTPUT.PUT_LINE('前提条件チェック: OK (現在バージョン: ' || v_version || ')');
END;
/

-- Step 2: DDL変更
PROMPT === Step 2: DDL変更 ===
@@ddl/001_add_columns.sql
@@ddl/002_create_tables.sql
@@ddl/003_create_indexes.sql

-- Step 3: データマイグレーション
PROMPT === Step 3: データマイグレーション ===
@@data/001_migrate_data.sql
@@data/002_update_references.sql

-- Step 4: PL/SQL オブジェクトの更新
PROMPT === Step 4: PL/SQLオブジェクト更新 ===
@@plsql/001_packages.sql
@@plsql/002_triggers.sql
@@plsql/003_views.sql

-- Step 5: コンパイルチェック
PROMPT === Step 5: 無効オブジェクトのチェック ===
DECLARE
    v_invalid NUMBER;
BEGIN
    SELECT COUNT(*) INTO v_invalid
    FROM user_objects
    WHERE status = 'INVALID';

    IF v_invalid > 0 THEN
        -- 無効オブジェクトの再コンパイル
        DBMS_UTILITY.COMPILE_SCHEMA(USER);

        SELECT COUNT(*) INTO v_invalid
        FROM user_objects
        WHERE status = 'INVALID';

        IF v_invalid > 0 THEN
            RAISE_APPLICATION_ERROR(-20002,
                v_invalid || ' 個の無効オブジェクトが残っています');
        END IF;
    END IF;
    DBMS_OUTPUT.PUT_LINE('無効オブジェクト: 0');
END;
/

-- Step 6: バージョン更新
PROMPT === Step 6: バージョン更新 ===
UPDATE schema_version
SET is_current = 'N'
WHERE schema_name = 'APP' AND is_current = 'Y';

INSERT INTO schema_version (schema_name, version, deployed_at, deployed_by, is_current)
VALUES ('APP', '2.0', SYSTIMESTAMP, USER, 'Y');

COMMIT;

PROMPT ================================================================
PROMPT デプロイメント v2.0 完了
PROMPT 日時: &_DATE
PROMPT ================================================================

SPOOL OFF
EXIT 0

19.4 データ検証スクリプト

-- data_validation.sql
-- デプロイ後のデータ検証

SET SERVEROUTPUT ON SIZE UNLIMITED
SET FEEDBACK OFF

DECLARE
    v_errors NUMBER := 0;

    PROCEDURE check_rule(p_name VARCHAR2, p_query VARCHAR2, p_expected NUMBER) IS
        v_actual NUMBER;
    BEGIN
        EXECUTE IMMEDIATE p_query INTO v_actual;
        IF v_actual != p_expected THEN
            DBMS_OUTPUT.PUT_LINE('[FAIL] ' || p_name ||
                ' - 期待値: ' || p_expected || ', 実際値: ' || v_actual);
            v_errors := v_errors + 1;
        ELSE
            DBMS_OUTPUT.PUT_LINE('[PASS] ' || p_name);
        END IF;
    EXCEPTION
        WHEN OTHERS THEN
            DBMS_OUTPUT.PUT_LINE('[ERROR] ' || p_name || ' - ' || SQLERRM);
            v_errors := v_errors + 1;
    END;

BEGIN
    DBMS_OUTPUT.PUT_LINE('=== データ検証開始 ===');
    DBMS_OUTPUT.PUT_LINE('');

    -- 検証ルールの実行
    check_rule('社員テーブルの行数',
        'SELECT COUNT(*) FROM employees', 107);

    check_rule('部門テーブルの行数',
        'SELECT COUNT(*) FROM departments', 27);

    check_rule('NULL給与の件数',
        'SELECT COUNT(*) FROM employees WHERE salary IS NULL', 0);

    check_rule('孤立レコードの確認',
        'SELECT COUNT(*) FROM employees e ' ||
        'WHERE NOT EXISTS (SELECT 1 FROM departments d WHERE d.department_id = e.department_id)',
        1);  -- employee_id = 178 のみ

    check_rule('無効オブジェクトの確認',
        'SELECT COUNT(*) FROM user_objects WHERE status = ''INVALID''', 0);

    DBMS_OUTPUT.PUT_LINE('');
    DBMS_OUTPUT.PUT_LINE('=== 検証完了 ===');
    IF v_errors > 0 THEN
        DBMS_OUTPUT.PUT_LINE('エラー: ' || v_errors || ' 件');
        RAISE_APPLICATION_ERROR(-20099, v_errors || ' 件の検証エラーがあります');
    ELSE
        DBMS_OUTPUT.PUT_LINE('すべての検証に合格しました');
    END IF;
END;
/

19.5 並列処理パターン

シェルスクリプトと組み合わせて、複数のSQL*Plus プロセスを並列実行するパターンである。

#!/bin/bash
# parallel_export.sh - 複数テーブルの並列エクスポート

MAX_PARALLEL=4
EXPORT_DIR=/home/oracle/exports/$(date +%Y%m%d)
mkdir -p ${EXPORT_DIR}

# テーブル一覧の取得
TABLES=$(sqlplus -S hr/password@ORCL <<'EOF'
SET HEADING OFF FEEDBACK OFF PAGESIZE 0
SELECT table_name FROM user_tables ORDER BY table_name;
EXIT;
EOF
)

# 並列エクスポート
RUNNING=0
for TABLE in ${TABLES}; do
    (
        echo "=== エクスポート開始: ${TABLE} ==="
        sqlplus -S hr/password@ORCL <<EOF > ${EXPORT_DIR}/${TABLE}.csv
SET LINESIZE 32767
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET COLSEP ','
SET TRIMSPOOL ON

SELECT * FROM ${TABLE};
EXIT;
EOF
        echo "=== エクスポート完了: ${TABLE} ==="
    ) &

    RUNNING=$((RUNNING + 1))
    if [ ${RUNNING} -ge ${MAX_PARALLEL} ]; then
        wait -n
        RUNNING=$((RUNNING - 1))
    fi
done

# すべてのジョブの完了を待機
wait
echo "全テーブルのエクスポートが完了しました"

20. クラウド環境での利用

20.1 Oracle Cloud Infrastructure (OCI) への接続

OCI 上の Oracle Database に SQL*Plus から接続する方法を解説する。

DB System (VM/BM) への接続

# パブリックIPアドレスを使用(開発環境)
sqlplus admin/password@"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<public-ip>)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=<pdb-service-name>)))"

# プライベートIPアドレスを使用(本番環境、VPN/FastConnect経由)
sqlplus admin/password@"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.0.1.100)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdb1.subnet.vcn.oraclevcn.com)))"

# tnsnames.ora の設定
# OCI_DB =
#   (DESCRIPTION =
#     (ADDRESS = (PROTOCOL = TCP)(HOST = 10.0.1.100)(PORT = 1521))
#     (CONNECT_DATA = (SERVICE_NAME = pdb1.subnet.vcn.oraclevcn.com))
#   )
sqlplus admin/password@OCI_DB

20.2 Autonomous Database への接続

Autonomous Database (ADB) は mTLS による暗号化接続が必要であり、ウォレットファイルを使用する。

ウォレットのダウンロードと設定

# OCI CLI でウォレットをダウンロード
oci db autonomous-database generate-wallet \
  --autonomous-database-id ocid1.autonomousdatabase.oc1... \
  --password WalletPassword123 \
  --file /tmp/wallet.zip

# ウォレットの展開
mkdir -p /opt/oracle/wallet/adb
cd /opt/oracle/wallet/adb
unzip /tmp/wallet.zip

# ウォレットディレクトリの内容
# cwallet.sso       - 自動ログインウォレット
# ewallet.p12       - PKCS#12 ウォレット
# sqlnet.ora         - ネットワーク設定
# tnsnames.ora       - TNS設定
# ojdbc.properties   - JDBC設定
# keystore.jks       - Java キーストア
# truststore.jks     - Java トラストストア

sqlnet.ora の設定

# /opt/oracle/wallet/adb/sqlnet.ora
WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="/opt/oracle/wallet/adb")))
SSL_SERVER_DN_MATCH=yes

環境変数の設定と接続

# 環境変数の設定
export TNS_ADMIN=/opt/oracle/wallet/adb

# tnsnames.ora の接続名を確認
cat /opt/oracle/wallet/adb/tnsnames.ora
# myatp_high, myatp_medium, myatp_low, myatp_tp, myatp_tpurgent 等

# 接続
sqlplus admin/MyPassword@myatp_medium

# 接続確認
SQL> SELECT SYS_CONTEXT('USERENV', 'DB_NAME') FROM dual;
SQL> SELECT SYS_CONTEXT('USERENV', 'CLOUD_SERVICE') FROM dual;

mTLS なしの接続(Oracle 19c 以降、ADB設定で許可した場合)

# TLS のみ(ウォレット不要)で接続
sqlplus admin/password@'(description=(retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=adb.ap-tokyo-1.oraclecloud.com))(connect_data=(service_name=xxx_medium.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))'

20.3 Docker 環境での SQL*Plus

Oracle Instant Client Docker イメージ

# Dockerfile
FROM oraclelinux:8-slim

# Oracle Instant Client のインストール
RUN dnf install -y oracle-instantclient-release-el8 && \
    dnf install -y oracle-instantclient-basic oracle-instantclient-sqlplus && \
    dnf clean all

# 環境変数の設定
ENV ORACLE_HOME=/usr/lib/oracle/21/client64
ENV PATH=$ORACLE_HOME/bin:$PATH
ENV LD_LIBRARY_PATH=$ORACLE_HOME/lib
ENV TNS_ADMIN=/opt/oracle/network/admin
ENV NLS_LANG=JAPANESE_JAPAN.AL32UTF8

# TNS設定ディレクトリの作成
RUN mkdir -p $TNS_ADMIN

# スクリプトディレクトリの作成
RUN mkdir -p /opt/oracle/scripts

# 作業ディレクトリ
WORKDIR /opt/oracle/scripts

# デフォルトコマンド
CMD ["sqlplus", "/nolog"]

Docker での実行

# イメージのビルド
docker build -t oracle-sqlplus .

# 対話的な使用
docker run -it --rm \
  -v /path/to/tnsnames.ora:/opt/oracle/network/admin/tnsnames.ora \
  -v /path/to/scripts:/opt/oracle/scripts \
  oracle-sqlplus

# バッチ実行
docker run --rm \
  -v /path/to/tnsnames.ora:/opt/oracle/network/admin/tnsnames.ora \
  -v /path/to/scripts:/opt/oracle/scripts \
  oracle-sqlplus \
  sqlplus -S scott/tiger@ORCL @/opt/oracle/scripts/daily_report.sql

# ウォレットを使用した ADB 接続
docker run -it --rm \
  -v /path/to/wallet:/opt/oracle/wallet \
  -e TNS_ADMIN=/opt/oracle/wallet \
  oracle-sqlplus \
  sqlplus admin/password@myatp_medium

20.4 CI/CD パイプラインでの活用

GitHub Actions の例

# .github/workflows/db-deploy.yml
name: Database Deployment

on:
  push:
    branches: [main]
    paths: ['db/**']

jobs:
  deploy:
    runs-on: ubuntu-latest
    container:
      image: container-registry.oracle.com/database/instantclient:21

    steps:
      - uses: actions/checkout@v4

      - name: Setup Oracle Wallet
        run: |
          mkdir -p /opt/oracle/wallet
          echo "${{ secrets.ORACLE_WALLET }}" | base64 -d > /tmp/wallet.zip
          unzip /tmp/wallet.zip -d /opt/oracle/wallet

      - name: Set Environment
        run: |
          echo "TNS_ADMIN=/opt/oracle/wallet" >> $GITHUB_ENV
          echo "NLS_LANG=AMERICAN_AMERICA.AL32UTF8" >> $GITHUB_ENV

      - name: Run Database Migration
        run: |
          sqlplus -S "${{ secrets.DB_USER }}/${{ secrets.DB_PASSWORD }}@${{ secrets.DB_CONNECTION }}" \
            @db/deploy.sql
        env:
          TNS_ADMIN: /opt/oracle/wallet

      - name: Run Validation
        run: |
          sqlplus -S "${{ secrets.DB_USER }}/${{ secrets.DB_PASSWORD }}@${{ secrets.DB_CONNECTION }}" \
            @db/validate.sql

20.5 Kubernetes 環境での活用

# sqlplus-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration-job
spec:
  template:
    spec:
      containers:
      - name: sqlplus
        image: container-registry.oracle.com/database/instantclient:21
        command: ["sqlplus", "-S"]
        args: ["$(DB_USER)/$(DB_PASSWORD)@$(DB_CONNECTION)", "@/scripts/migrate.sql"]
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: password
        - name: DB_CONNECTION
          value: "mydb_medium"
        - name: TNS_ADMIN
          value: "/wallet"
        - name: NLS_LANG
          value: "JAPANESE_JAPAN.AL32UTF8"
        volumeMounts:
        - name: wallet-volume
          mountPath: /wallet
          readOnly: true
        - name: scripts-volume
          mountPath: /scripts
          readOnly: true
      volumes:
      - name: wallet-volume
        secret:
          secretName: oracle-wallet
      - name: scripts-volume
        configMap:
          name: db-scripts
      restartPolicy: Never
  backoffLimit: 3

21. トラブルシューティング

21.1 接続エラー

ORA-12154: TNS:could not resolve the connect identifier specified

最も頻発する接続エラーの一つである。TNS 名前解決に失敗した場合に発生する。

# 原因の切り分け手順

# 1. TNS_ADMIN 環境変数の確認
echo $TNS_ADMIN
# 未設定の場合: $ORACLE_HOME/network/admin が使用される

# 2. tnsnames.ora の存在確認
ls -la $TNS_ADMIN/tnsnames.ora
# または
ls -la $ORACLE_HOME/network/admin/tnsnames.ora

# 3. tnsnames.ora の内容確認(タイプミス、書式エラー)
cat $TNS_ADMIN/tnsnames.ora

# 4. tnsping で名前解決テスト
tnsping ORCL

# 5. sqlnet.ora の名前解決順序を確認
cat $TNS_ADMIN/sqlnet.ora
# NAMES.DIRECTORY_PATH = (TNSNAMES, LDAP, EZCONNECT)

ORA-12541: TNS:no listener

リスナーが起動していないか、指定したホスト/ポートでリスナーが待ち受けていない場合に発生する。

# リスナーの状態確認
lsnrctl status

# リスナーの起動
lsnrctl start

# 特定のリスナー名を指定
lsnrctl status LISTENER_ORCL

# ネットワーク接続の確認
telnet dbserver 1521
# または
nc -zv dbserver 1521

ORA-12170: TNS:Connect timeout occurred

ネットワークの問題によりタイムアウトが発生した場合のエラーである。

# ネットワーク疎通の確認
ping dbserver

# ポートの疎通確認
nc -zv dbserver 1521

# ファイアウォールの確認
iptables -L -n | grep 1521

# sqlnet.ora でタイムアウト値を調整
# SQLNET.INBOUND_CONNECT_TIMEOUT = 60
# SQLNET.RECV_TIMEOUT = 30
# SQLNET.SEND_TIMEOUT = 30

ORA-01017: invalid username/password; logon denied

-- パスワードの大文字小文字を確認(Oracle 11g以降はデフォルトで大文字小文字を区別)
SQL> SHOW PARAMETER sec_case_sensitive_logon
-- TRUE の場合、パスワードの大文字小文字を正確に入力する必要がある

-- アカウントのロック状態を確認
SQL> SELECT username, account_status, lock_date, expiry_date
  2  FROM dba_users
  3  WHERE username = 'SCOTT';

-- アカウントのロック解除
SQL> ALTER USER scott ACCOUNT UNLOCK;

-- パスワードのリセット
SQL> ALTER USER scott IDENTIFIED BY new_password;

21.2 文字セットの問題

文字化けの対処

# NLS_LANG の確認と設定
echo $NLS_LANG

# 正しい設定例(UTF-8環境の場合)
export NLS_LANG=JAPANESE_JAPAN.AL32UTF8

# データベースの文字セットを確認
sqlplus -S / as sysdba <<'EOF'
SELECT parameter, value FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
EXIT;
EOF

# ターミナルのロケールを確認
locale

# NLS_LANG の構成要素
# NLS_LANG = <言語>_<地域>.<文字セット>
# 例:
#   JAPANESE_JAPAN.AL32UTF8         (日本語, UTF-8)
#   AMERICAN_AMERICA.AL32UTF8       (英語, UTF-8)
#   JAPANESE_JAPAN.JA16SJISTILDE    (日本語, Shift_JIS)
#   JAPANESE_JAPAN.JA16EUC          (日本語, EUC-JP)

スプールファイルの文字コード

-- UTF-8 でスプール出力するための設定
-- NLS_LANG が AL32UTF8 に設定されていることを確認

-- BOM (Byte Order Mark) 付き UTF-8 で出力する場合
-- (Excel で UTF-8 CSV を開く際に必要な場合がある)
SET PAGESIZE 0
SET HEADING OFF
SET FEEDBACK OFF
SET TRIMSPOOL ON

SPOOL /home/oracle/exports/data_utf8bom.csv
-- BOM の出力
SELECT CHR(239) || CHR(187) || CHR(191) FROM dual;
-- データの出力
SELECT employee_id || ',' || first_name || ',' || last_name
FROM employees;
SPOOL OFF

21.3 スプール関連の問題

スプールファイルに余分な空白が入る

-- 行末の空白を削除
SET TRIMSPOOL ON
SET TRIMOUT ON

-- LINESIZEを適切に設定(大きすぎると空白が入る)
SET LINESIZE 200   -- 必要最小限に設定

スプールファイルに SQL文やプロンプトが入る

-- SQL文のエコーを抑制
SET ECHO OFF

-- SQL*Plus プロンプトを抑制
SET TERMOUT OFF     -- 画面出力を抑制(スプールには出力される)

-- フィードバックを抑制
SET FEEDBACK OFF

-- ヘッダーを抑制
SET HEADING OFF

-- ページ区切りを抑制
SET PAGESIZE 0

21.4 パフォーマンスの問題

SQL*Plus が遅い場合のチェックポイント

-- 1. ネットワークレイテンシの確認
SET TIMING ON
SELECT 1 FROM dual;
-- Elapsed が 100ms 以上ならネットワークの問題

-- 2. ARRAYSIZE の調整(大量データ取得時)
SET ARRAYSIZE 100   -- デフォルト15、大量データ時は100-5000に
SHOW ARRAYSIZE

-- 3. 不要な出力の抑制
SET TERMOUT OFF
SET FEEDBACK OFF
SET PAGESIZE 0

-- 4. login.sql の最適化
-- 重いクエリを login.sql に含めていないか確認
-- ALTER SESSION コマンドが多すぎないか確認

-- 5. SET APPINFO による負荷
-- SET APPINFO OFF  -- V$SESSION.MODULE/ACTION の更新を停止

21.5 SQL*Plus 固有のエラー (SP2-xxxx)

エラーコードメッセージ原因対処
SP2-0042unknown command不明なコマンドコマンド名のスペルを確認
SP2-0310unable to open fileファイルが見つからないパスとファイル名を確認
SP2-0332Cannot create spool fileスプールファイル作成不可ディレクトリの存在と書き込み権限を確認
SP2-0382command has no effectコマンドが無効SET コマンドの値が適切か確認
SP2-0552Bind variable not declaredバインド変数未宣言VARIABLE コマンドで宣言する
SP2-0618Session terminatedセッション切断ネットワークやタイムアウトを確認
SP2-0640Not connected未接続CONNECT コマンドで再接続
SP2-0734unknown command beginningコマンド認識エラーSQL*Plus コマンドの構文を確認
SP2-1503Unable to initialize Oracle call interfaceOCI初期化エラーORACLE_HOME と共有ライブラリパスを確認

21.6 よくある落とし穴

セミコロンの二重入力

-- 間違い: PL/SQL ブロックの後にセミコロンとスラッシュの両方
BEGIN
    DBMS_OUTPUT.PUT_LINE('Hello');
END;
;   -- ← この余分なセミコロンがエラーの原因
/

-- 正しい:
BEGIN
    DBMS_OUTPUT.PUT_LINE('Hello');
END;
/

& 文字を含むデータの挿入

-- 問題: & が代入変数として解釈される
SQL> INSERT INTO companies (name) VALUES ('AT&T');
Enter value for T:   -- ← & が代入変数として解釈される

-- 解決策1: SET DEFINE OFF
SQL> SET DEFINE OFF
SQL> INSERT INTO companies (name) VALUES ('AT&T');

-- 解決策2: エスケープ文字の設定
SQL> SET ESCAPE '\'
SQL> INSERT INTO companies (name) VALUES ('AT\&T');

-- 解決策3: CHR関数の使用
SQL> INSERT INTO companies (name) VALUES ('AT' || CHR(38) || 'T');

CLOB データの表示

-- 問題: CLOB データが切り捨てられる
SQL> SELECT clob_column FROM my_table;
-- デフォルトでは先頭80文字のみ表示

-- 解決策: SET LONG と SET LONGCHUNKSIZE を設定
SQL> SET LONG 100000
SQL> SET LONGCHUNKSIZE 100000
SQL> SELECT clob_column FROM my_table;

22. 運用ベストプラクティスとまとめ

22.1 スクリプト命名規則

一貫性のある命名規則を採用することで、スクリプトの管理が容易になる。

推奨命名パターン:

DDL スクリプト:
  ddl_<操作>_<オブジェクト名>.sql
  例: ddl_create_employees.sql
      ddl_alter_orders_add_column.sql
      ddl_drop_temp_tables.sql

DML スクリプト:
  dml_<操作>_<対象>.sql
  例: dml_insert_initial_data.sql
      dml_update_salary.sql
      dml_delete_old_logs.sql

バッチスクリプト:
  batch_<頻度>_<処理名>.sql
  例: batch_daily_stats_gather.sql
      batch_weekly_cleanup.sql
      batch_monthly_report.sql

デプロイスクリプト:
  deploy_v<バージョン>_<ステップ番号>_<説明>.sql
  例: deploy_v2.0_001_create_tables.sql
      deploy_v2.0_002_migrate_data.sql
      deploy_v2.0_003_update_packages.sql

管理スクリプト:
  admin_<操作>.sql
  例: admin_check_tablespace.sql
      admin_kill_sessions.sql
      admin_gather_stats.sql

22.2 ディレクトリ構造

/home/oracle/scripts/
├── admin/                  # 管理スクリプト
│   ├── startup.sql
│   ├── shutdown.sql
│   ├── check_health.sql
│   └── gather_stats.sql
├── batch/                  # バッチ処理
│   ├── daily/
│   │   ├── batch_daily_cleanup.sql
│   │   └── batch_daily_report.sql
│   ├── weekly/
│   │   └── batch_weekly_summary.sql
│   └── monthly/
│       └── batch_monthly_archive.sql
├── deploy/                 # デプロイスクリプト
│   ├── v1.0/
│   ├── v1.1/
│   └── v2.0/
│       ├── deploy_v2.0.sql         # メインスクリプト
│       ├── ddl/
│       │   ├── 001_create_tables.sql
│       │   └── 002_create_indexes.sql
│       ├── data/
│       │   └── 001_migrate_data.sql
│       ├── plsql/
│       │   └── 001_packages.sql
│       └── rollback/
│           └── rollback_v2.0.sql
├── export/                 # データエクスポート
│   ├── export_employees.sql
│   └── export_orders.sql
├── lib/                    # 共通ライブラリ
│   ├── common_settings.sql
│   ├── error_handler.sql
│   └── logging.sql
├── monitor/                # モニタリング
│   ├── check_locks.sql
│   ├── check_sessions.sql
│   └── check_performance.sql
├── login.sql               # 個人設定
└── README.txt              # スクリプト一覧と説明

22.3 ログ出力のベストプラクティス

-- logging.sql - 共通ログ出力ライブラリ

-- ログファイル名の生成
COLUMN log_timestamp NEW_VALUE v_log_ts NOPRINT
SELECT TO_CHAR(SYSDATE, 'YYYYMMDD_HH24MISS') AS log_timestamp FROM dual;

-- ログディレクトリの設定
DEFINE log_dir = '/var/log/oracle/scripts'

-- ログ出力の標準テンプレート
-- スクリプト内での使用方法:
--   DEFINE script_name = 'daily_batch'
--   @lib/logging.sql

SPOOL &log_dir./&script_name._&v_log_ts..log

PROMPT ================================================================
PROMPT Script:    &script_name..sql
PROMPT StartTime: &_DATE
PROMPT User:      &_USER
PROMPT Database:  &_CONNECT_IDENTIFIER
PROMPT ================================================================

22.4 セキュリティのベストプラクティス

# 1. パスワードをスクリプトにハードコードしない
# 悪い例:
sqlplus scott/tiger@ORCL @script.sql

# 良い例: ウォレットを使用
sqlplus /@ORCL @script.sql

# 良い例: 環境変数を使用(次善策)
export DB_CONN="scott@ORCL"
sqlplus ${DB_CONN} @script.sql
# (パスワードは対話的に入力、またはウォレットから取得)

# 2. スクリプトファイルの権限を適切に設定
chmod 700 /home/oracle/scripts/admin/
chmod 600 /home/oracle/scripts/admin/*.sql

# 3. ログファイルにパスワードが含まれないようにする
# SET ECHO OFF を使用
# CONNECT 文のパスワードが表示されないようにする

# 4. 制限モードの活用
sqlplus -R 2 scott@ORCL @report.sql
# SPOOL や HOST コマンドが無効になる

22.5 デプロイメントのベストプラクティス

-- デプロイメントチェックリスト用スクリプト

-- 1. バックアップの確認
PROMPT [CHECK] バックアップの確認
SELECT completion_time, input_bytes_display, status
FROM v$rman_backup_job_details
WHERE start_time > SYSDATE - 1
ORDER BY start_time DESC
FETCH FIRST 5 ROWS ONLY;

-- 2. 現在のバージョンの確認
PROMPT [CHECK] 現在のスキーマバージョン
SELECT schema_name, version, deployed_at
FROM schema_version
WHERE is_current = 'Y';

-- 3. アクティブセッションの確認
PROMPT [CHECK] アクティブセッション数
SELECT COUNT(*) AS active_sessions
FROM v$session
WHERE status = 'ACTIVE' AND type = 'USER';

-- 4. 実行中のジョブの確認
PROMPT [CHECK] 実行中のジョブ
SELECT job_name, state, last_start_date
FROM dba_scheduler_jobs
WHERE state = 'RUNNING';

-- 5. テーブルスペースの空き容量
PROMPT [CHECK] テーブルスペース空き容量
SELECT tablespace_name,
       ROUND(SUM(bytes)/1024/1024) AS total_mb,
       ROUND(SUM(free_bytes)/1024/1024) AS free_mb
FROM (
    SELECT df.tablespace_name, df.bytes,
           NVL(fs.free_bytes, 0) AS free_bytes
    FROM dba_data_files df
    LEFT JOIN (
        SELECT tablespace_name, file_id, SUM(bytes) AS free_bytes
        FROM dba_free_space GROUP BY tablespace_name, file_id
    ) fs ON df.tablespace_name = fs.tablespace_name AND df.file_id = fs.file_id
)
GROUP BY tablespace_name
HAVING ROUND(SUM(free_bytes)/SUM(bytes)*100) < 20
ORDER BY tablespace_name;

22.6 マイグレーションチェックリスト

Oracle Database のバージョンアップやプラットフォーム移行時の SQL*Plus 関連チェックリストを以下に示す。

#確認項目確認方法注意事項
1SQL*Plus バージョンの互換性sqlplus -Vクライアントとサーバーのバージョン差
2NLS_LANG 設定echo $NLS_LANG文字セットの一致
3tnsnames.ora の更新ファイル確認新環境のホスト/ポート/サービス名
4sqlnet.ora の更新ファイル確認暗号化設定、タイムアウト値
5login.sql の互換性テスト実行非推奨機能の使用有無
6glogin.sql の互換性テスト実行新バージョン固有の設定
7スクリプトの動作確認テスト環境で実行非互換SQL文の特定
8ウォレット設定接続テスト新環境の証明書
9SET コマンドの互換性SHOW ALL で確認新規/廃止された SET オプション
10環境変数の確認env コマンドORACLE_HOME、PATH等

22.7 まとめ

SQLPlus は 40 年以上の歴史を持つ Oracle Database の標準コマンドラインインターフェースである。GUI ツールやモダンな CLIツール(SQLcl)が登場した現在でも、以下の理由から SQLPlus は不可欠な存在であり続けている。

SQL*Plus が不可欠な理由

  1. ゼロ依存性: Oracle Database に標準付属し、追加インストールが不要
  2. 自動化の基盤: シェルスクリプトやCI/CDパイプラインとの連携が容易
  3. 管理操作の必須ツール: STARTUP/SHUTDOWN はSQL*Plus(またはRMAN)でのみ可能
  4. 軽量性: SSH経由のリモートアクセスでも快適に動作
  5. 再現性: スクリプトによる操作の完全な再現が可能
  6. 緊急対応: GUIが使えない障害時の最終手段

効果的な活用のポイント

  1. login.sql / glogin.sql のカスタマイズ: 作業効率を大幅に向上させる
  2. WHENEVER SQLERROR の適切な使用: 堅牢なスクリプトの基盤
  3. SPOOL の活用: レポート生成とデータエクスポートの自動化
  4. 変数の使い分け: 代入変数とバインド変数の適切な使い分け
  5. SET コマンドの熟知: 出力制御と動作制御の完全な理解
  6. エラーハンドリング: 本番運用に耐える堅牢なスクリプト設計
  7. セキュリティ: ウォレット認証の活用とパスワード管理

本ガイドで解説した内容を習得することで、SQL*Plus を単なるSQL実行ツールとしてではなく、Oracle Database の運用・管理・自動化を支える強力なプラットフォームとして活用できるようになるだろう。


参考文献・関連リソース

  • Oracle SQL*Plus User's Guide and Reference (Oracle Documentation)
  • Oracle Database Administrator's Guide
  • Oracle Database SQL Language Reference
  • Oracle Database PL/SQL Language Reference
  • Oracle Instant Client Downloads (oracle.com/database/technologies/instant-client)
  • SQLcl Documentation (oracle.com/database/sqldeveloper/technologies/sqlcl)