「データベース」タグアーカイブ

Oracle:COALESCE関数の使い方

oracleの独自関数のCOALESCE(コアレス)関数の用途についてメモしておきます。

COALESCE関数とは

COALESCE関数は引数のリストから最初のNULL以外の値を返却するOracle独自関数となります。

NVL2関数との違いは必ずしも引数へ指定するデータ型を全て合わせる必要はないことです。

ただデータの一貫性を保ちたい場合は極力データ型は合わせた方が望ましいです。

サンプルテーブル

  • サンプルテーブル「CLIENT_ADDRESS」

COALESCE関数の使用例

  • SQL(クエリー)例

    上記例ではSTART_DATEがNULLであればEND_DATEの値を、END_DATEもNULLであればsysdateを返却します。

  • 実行結果

Oracle:NVL関数とNVL2関数の違い

oracleの独自関数としてNVL関数やNVL2関数があります。

知ってると結構便利な関数なので、この2つの関数の違いについて整理しておきます。

NVL関数とは

NVL関数は第1引数がNULLなら第2引数の値(代替値)を返します。

もし第1引数の結果がNULLでなければ、そのまま第1引数の値を返します。

注意点として第1引数と第2引数へは同じデータ型を指定する必要があります。

NVL関数の使用例

  • サンプルテーブル「CLIENT_ADDRESS」
  • SQL(クエリー)例
    以下の例ではEND_DATEがNULLでない場合はEND_DATEの値を、NULLの場合はsysdateを返却します。
  • 実行結果

NVL2関数とは

NVL2関数は第1引数がNULLの場合に、第2引数の値を返却し、第1引数がNULLの場合は第3引数の値を返却します。

注意点として第1引数、第2引数、第3引数に指定する値は全て同じデータ型を指定する必要があります。

NVL2関数の使用例

  • サンプルテーブル「CLIENT_ADDRESS」
  • SQL(クエリー)例
    以下の例ではEND_DATEがNULLでない場合は第2引数のSTART_DATEの値を返却し、END_DATEがNULLの場合は第3引数のsysdateを返却します。
  • 実行結果

補足:実務での利用上の注意と代替案のご提案

Oracle の NVLNVL2 関数は便利な反面、以下のような点に留意して使うとより安全・効率的です。

  1. データ型制約に注意する
    NVL/NVL2 では、引数に与える値が「同じデータ型」でなければなりません(Oracle の仕様)という制約があります。
    たとえば、日付型と文字列型を混在させて使おうとすると、意図しない型変換やエラーを招く可能性があります。

  2. NULL の扱いが複雑な場合には COALESCE の利用も検討する
    複数の候補値を順番に評価して最初に NULL でないものを返すような処理をしたい場合は、NVL/NVL2 よりも COALESCE のほうが可読性・拡張性の面で優れるケースがあります。
    たとえば、複数の列を順番にチェックして最初の非 NULL 値を採りたいときなどには COALESCE のほうが直感的に記述できます。

  3. パフォーマンス面の配慮
    NULL チェック・代替値の置き換えという処理自体は軽い操作ですが、複雑な SQL や大規模データセットで組み合わされると、意図せぬオーバーヘッドになることがあります。
    特にインデックス条件や結合条件の中で使う場合は、実行プランを確認して予期せぬフルスキャンなどになっていないか注意しましょう。

  4. 意図の可視化
    関数を多用するクエリは読みづらくなりがちです。
    「なぜこの列で NULL チェックをするのか」「代替値にはなぜこの値を選んだか」といった背景を、コメントやドキュメントとして残しておくと、後から見直すときに助けになります。

INSERT文を指定回数分ループして実行する方法

性能試験などであるテーブルに大量データの作成が必要になった場合にINSERT文をループで処理できれば便利!という事で、SQLとロジックを組み合わせたストアドプロシージャでのサンプルプログラムとなります。

ストアドプロシージャ

上記の例では、loop_limitに指定した件数分「GOODS」テーブルへレコードを追加するサンプルコードです。

上記の例では、loop_limitを10としていますが、必要に応じて任意の数値に変更できます。

DBeaverで上記のストアドプロシージャを実行する場合は「SQLスクリプトを実行する」を選択することで正常に実行されます。

実行結果

 

Oracle:事前構成済の表領域

Oracleではデータベースを作成すると自動的に以下の表領域が作成されます。

事前構成済の表領域

 

表領域説明
SYSTEMOracleサーバーがデータベースを管理するために使用する表領域
SYSAUXSYSTEM表領域の補助表領域
TEMPデータベースのデフォルトの一時表領域
UNDOTBS1UNDO表領域
USERS永続表領域
SYSやSYSTEMユーザー以外のユーザー用のデフォルト表領域
EXAMPLEデータベース作成時に「サンプル・スキーマの作成」を指定すると作成される表領域
 

Oracle:データベースの起動段階と状態について

Oracleデータベースを起動すると内部的に以下の段階でデータベースが使用可能な状態となります。

データベースの起動段階と状態

 

段階ステータス状態
1SHUTDOWNデータベースが停止している状態
2NOMOUNTインスタンスが起動している状態
※制御ファイル、データファイル、REDOログファイルはクローズ
3MOUNTインスタンスが起動し、制御ファイルがオープンしている状態
※データファイル、REDOログファイルはクローズ
4OPENインスタンスが起動し、制御ファイル、データファイル、REDOログ・ファイルもオープンしている状態
※一般ユーザーが使用可能な状態
 

Oracle:制約の種類

Oracleデータベースでは以下の制約を設定することが出来ます。

Oracle DB:制約の種類

制約説明
NOT NULL制約NULL値の設定を許可しない
UNIQE制約
(一意キー制約)
一意の値のみ許可します。複数レコード登録時、重複する値を許可しません。NULL値は許可します。
CHECK制約指定した条件の値のみ許可します。
PRIMARY KEY制約
(主キー制約)
一意の値のみ許可し、重複する値は許可しません。NULL値も許可しません。
FOREIGN KEY制約
(外部キー制約)
指定した親テーブルに存在する値のみ許可します。
 

制約のポイント

  • 制約はCREATE TABLE または ALTER TABLEで設定出来ます。
  • 制約設定の構文には列制約構文と表制約構文の2種類あります。
  • NOT NULL制約は列制約構文でのみ設定出来ます。

制約の設定例

  • 下記例のNOT NULL制約の設定箇所が列制約構文、UNIQUE制約の設定箇所が表制約構文となります。

 

SQL:特定の日付時点で有効な住所情報を取得する方法

顧客の有効住所などを管理しているテーブルからある特定の日付時点で有効な住所を取得する方法をメモしておきます。

特定の日付時点で有効な住所情報を取得するサンプル

サンプルテーブル

  • 「CLIENT_ADDRESS」テーブル
    以下の様に顧客ID(CLIENT_ID)毎に有効な住所を管理するテーブルです。最新の住所のEND_DATEはnullとして管理してます。

クエリー(SQL)

  • ‘2022-03-31’時点で有効な住所情報を取得する例です。

実行結果

Oracle:プロセス構造の仕組み

Oracle DBのプロセス構造は大きく「ユーザープロセス」、「サーバープロセス」、「バックグラウンドプロセス」があります。

ユーザープロセス

  • クライアントからSQLを発行すると発生するプロセスです。

サーバープロセス

  • クライアントが発行したSQLを処理するするのがメインのプロセスです。

バックグラウンドプロセス

  • サーバープロセスがSQL管理に専念させるため、他のプロセスを監視するためのプロセスです。Oracleインスタンスを起動することで自動で起動します。
  • 主なバッググランドプロセスの種類
    種類説明
    DBWn
    (データベースライター)
    データベースバッファキャッシュ内の変更されたデータをデータファイルへ書き込む
    LGWR
    (ログライター)
    REDOログバッファにあるREDOログをREDOログファイルへ書き込む
    CKPT
    (チェックポイント)
    チェックポイント情報を制御ファイルとデータファイルヘッダーへ書き込む
    SMON
    (システムモニター)
    インスタンスのリカバリを実行する
    PMON
    (プロセスモニター)
    ユーザープロセス障害からリカバリを実施する
    ARCn
    (アーカイバー)
    REDOログファイルのコピー(アーカーブファイル)を作成する
    REDO
    (リカバラ)
    分散トランザクションに関する障害を自動的に解決する。
    MMON
    (マネージメントモニター)
    メモリー内の統計情報をスナップショットとして定期的にデーターベースへ格納する。
    MMAN
    (メモリーマネージャ)
    メモリーを必要な場所に動的に割り当てる

 

SQL:任意の順序でソート(並べ替え)する方法

SQLでは特定の項目の昇順、降順ではなく任意の順序で並べ替えて取得することも出来ます。

任意の順序でソートするにはORDER BY句でCASE文を指定する事で取得することが出来ます。

任意の順でソートする例

サンプルテーブル

「BIRTHDAY」テーブル

クエリー(SQL)

出力結果

SQL:xx日後、xxヶ月後、xx年後などの日付を取得する方法

SQLでsysdateなどの日付型へ加算、減算してxx日後、xxヶ月後、xx年後を求める方法をメモしておきます。

xx秒後、xx秒前を求める方法

クエリー(SQL)例

  • システム日付の30秒後と30秒前を取得する例です。

実行結果

 

xx分後、xx分前を求める方法

クエリー(SQL)例

  • システム日付の5分後と5分前を取得する例です。

実行結果

 

xx時間後、xx時間前を求める方法

クエリー(SQL)例

  • システム日付の2時間後と2時間前を取得する例です。

実行結果

 

xx日後、xx日前を求める方法

クエリー(SQL)例

  • システム日付の1日後と1日前を取得する例です。

実行結果

 

xxヶ月後、xxヶ月前を求める方法

クエリー(SQL)例

  • システム日付の1ヶ月後と1ヶ月前を取得する例です。ADD_MONTHS関数は1/31の1ヶ月後は2/28となるように上手く月末日を調整してくれます。

実行結果

 

xx年後、xx年前を求める方法

クエリー(SQL)例

  • システム日付の1年後と1年前を取得する例です。ADD_MONTHS関数に12の倍数を指定することで年単位での加減算が可能となります。

実行結果

 

補足:他データベースでの日付加算と実務での注意点

本記事では Oracle を前提に日付演算を紹介しましたが、他の主要データベースでも「xx日後/xxヶ月後/xx年後」を取得する方法が存在します。移植性や比較の参考として以下に整理します。

DBMS日数加算の例月・年加算の例
OracleSYSDATE + 3ADD_MONTHS(SYSDATE, 1)(1ヶ月後) / ADD_MONTHS(SYSDATE, 12)(1年後)
MySQLDATE_ADD(NOW(), INTERVAL 3 DAY)DATE_ADD(NOW(), INTERVAL 1 MONTH) / INTERVAL 1 YEAR
SQL ServerDATEADD(day, 3, GETDATE())DATEADD(month, 1, GETDATE())
PostgreSQLCURRENT_DATE + INTERVAL '3 day'+ INTERVAL '1 month' / '1 year'

月末日の扱いについて注意

  • Oracle の ADD_MONTHS('2024-01-31', 1)2024-02-29(存在しない日付は月末に補正)

  • MySQLやPostgreSQL でも同様に月末補正される場合があります

  • 契約更新日などで「きっちり同日を基準にしたい」場合は仕様確認が必要です

実務でよくある活用例

  • 支払期限:請求日+30日

  • 契約更新:契約開始日から6ヶ月後/1年後

  • リマインダー:イベント前7日/前1時間

  • 登録日を基準としたステップメール通知

減算にも応用可能

  • ADD_MONTHS(SYSDATE, -1) → 1ヶ月前

  • SYSDATE - 7 → 7日前


📌 上記を踏まえると、「日付加算はDBごとに関数が異なる」「月末や閏年の補正挙動を理解しておく」という点を意識しておくと、より安全なSQL設計につながります。