0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

複数テーブルから、現行データをビューで取得したときの躓き

Posted at

複数テーブルから、現行データをビューで取得したときの躓き

はじめに

Oracleで複数のテーブルから現行データだけをまとめたビューを作成しようとしたときに、
単純に結合して「古いデータが混ざる」「重複が増える」 といった問題が発生したので、そのときのポイントを備忘を兼ねて整理しました。

  • LEFT JOINとWHEREの条件の使い分け
  • TRUNCによる日付の比較

NG:WHERE に結合先の条件を書いた場合

SELECT *
FROM main_table main
LEFT JOIN secondary_records sec
    ON main.id = sec.main_id
WHERE TRUNC(sec.start_date) <= TRUNC(SYSDATE)
  AND (sec.end_date IS NULL OR TRUNC(sec.end_date) >= TRUNC(SYSDATE));

問題点

  • LEFT JOINなのにWHEREに条件を書いているため、INNER JOINのような挙動になる
  • 結合先に対応する行がNULLの場合、mainの行も除外される
  • 「結合先が存在しない現行データ」がビューに含まれなくなる

NG:TRUNC を使わず日付を比較する

SELECT *
FROM main_table
WHERE start_date <= SYSDATE
  AND (end_date IS NULL OR end_date >= SYSDATE);

問題点

  • OracleのDATE型は時刻まで持っているので、意図しない行が抽出されることがある

正しく抽出するために

LEFT JOIN で現行データを絞る

  • 結合時点で不要な行を除外できる
  • WHEREの条件がシンプルになる
LEFT JOIN secondary_records sec
  ON main.id = sec.main_id
  AND TRUNC(sec.start_date) <= TRUNC(SYSDATE)
  AND (sec.end_date IS NULL OR TRUNC(sec.end_date) >= TRUNC(SYSDATE))

TRUNCを使った日付比較

  • TRUNCによって時刻情報を切り捨て、日付単位で比較することで漏れや誤抽出を防止
SELECT *
FROM main_table
WHERE TRUNC(start_date) <= TRUNC(SYSDATE)
  AND (end_date IS NULL OR TRUNC(end_date) >= TRUNC(SYSDATE));

ビューの例

CREATE OR REPLACE VIEW v_current_records AS
SELECT DISTINCT 
    main.id,
    main.name,
    sec.info AS secondary_info,
    tert.info AS tertiary_info,
    main.start_date,
    COALESCE(main.end_date, sec.end_date, tert.end_date) AS end_date
FROM main_table main
LEFT JOIN secondary_records sec
    ON main.id = sec.main_id
    AND TRUNC(sec.start_date) <= TRUNC(SYSDATE)
    AND (sec.end_date IS NULL OR TRUNC(sec.end_date) >= TRUNC(SYSDATE))
LEFT JOIN tertiary_records tert
    ON main.id = tert.main_id
    AND TRUNC(tert.start_date) <= TRUNC(SYSDATE)
    AND (tert.end_date IS NULL OR TRUNC(tert.end_date) >= TRUNC(SYSDATE))
WHERE
    TRUNC(main.start_date) <= TRUNC(SYSDATE)
    AND (main.end_date IS NULL OR TRUNC(main.end_date) >= TRUNC(SYSDATE));

まとめ

  • LEFT JOINの条件に抽出したい条件を設定したほうがよい
  • dateでの比較はTRUNCで行う
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?