dポイントプレゼントキャンペーン実施中!

知識不足ですみませんが、
以下の場合の◎の内容が出力できるSQL文を教えてください。

同一のコードが複数あり、有効日時が異なる場合、更新日時に近いレコードを取得したいです。
テーブルの例を記述します。

---------------------------------------
tableA
---------------------------------------
コード | 名称 | 開始日時 | 終了日時
A01 | あ | 2012-04-01 |2014-03-01
A01 | 亜 | 2015-04-01 |2018-03-01
A02 | い | 2012-04-01 |2014-03-01
A02 | 位 | 2015-04-01 |2018-03-01
---------------------------------------
---------------------------------------
tableB
---------------------------------------
コード | 名称 | 開始日時 | 終了日時
B01 | う | 2012-04-01 |2014-03-01
B01 | 宇 | 2015-04-01 |2018-03-01
B02 | え | 2012-04-01 |2014-03-01
B02 | 絵 | 2015-04-01 |2018-03-01
---------------------------------------
---------------------------------------
tableC
---------------------------------------
Aコード | Bコード | 更新日時
A01 | B01 |2012-04-01
A02 | B02 |2013-04-01
A01 | B01 |2014-04-01
A02 | B02 |2015-04-01
---------------------------------------
---------------------------------------
◎SQLで出力したい内容◎
---------------------------------------
Aコード | A名称 | Bコード | B名称 | 更新日時
A01 | あ | B01 | う  | 2013-04-01
A02 | い | B02 | え  | 2014-04-01
A01 | 亜 | B01 | 宇  | 2015-04-01
A02 | 位 | B02 | 絵  | 2016-04-01
---------------------------------------

※DBはoracleです。プログラムに実装ではないので、sql文が知りたいです。

よろしくお願い致します。

質問者からの補足コメント

  • 回答ありがとうございます。
    * 更新日時に近いレコード、の判断方法
    →実は判断方法から悩ましいのですが、同一コードにおいて有効期間をかぶらないように登録する前提のため、
    ・更新日時より終了日時が大きい(=有効なデータである)
    ・かつ、終了日時が小さい(=直近)
    と判断しようと考えていました。
    なので、MIN(終了日時)で 更新日時<終了日時を条件にし
    AやBtblから名称を取得できればいいなと考えましたが、
    どうにも意図した出力ができません。

    * C.更新日時 → 出力したい内容.更新日時、の変換方法
    →すみません、イメージが間違ってました。
     C.更新日時と出力したい内容.更新日時は同一データの予定です。
    (変換の予定はなく、そのまま出力する形です。)
     Cの更新日時は、間違っており、Cの更新日時を、出力したい内容の更新日時に読み替えていただけますでしょうか。よろしくお願いいたします。

    No.1の回答に寄せられた補足コメントです。 補足日時:2015/03/10 18:10

A 回答 (4件)

めんどくさい検索条件が必要ならば SQL を使わないほうが良いです。


複雑怪奇な SQL は極端な性能劣化とかデッドロック発生とか保守性とか...

というわけで
テーブルを正規化して条件を簡単にしましょう
または
PL/SQL を書きましょう
    • good
    • 0

No.2 お礼への回答



> 日時比較に不等号ではなくbetweenを使う理由

たいした理由であはありませんが、between の方が性能が良いとされています。
実際の業務においては「A以上B未満」のケースもあるので、
全てに場合で使えるわけではありませんが。

あとは個人的に、こちらの方が読みやすいので。

> 結合にinner joinを使う理由を是非教えていただけますか。

C に対応する A,B が「必ず一つ」存在する前提で書いたので内部結合にしましたが、
必ず、でなければ以下のどちらかを選んでください。
* 内部結合 inner join で、問題の有るレコードを除外して出力
* 外部結合 left outer join で、問題の有るレコードでも穴あきで出力

あと、
> 他案③結合しない場合
それは内部結合を WHERE 句で書くやりかたです。
SQLが大規模化したときに、検索条件と結合条件がごっちゃになって
読みづらくなるのでオススメしません。

Oracle8 の頃は SQL92 標準の JOIN 句が使えなかったり、
Oracle9 で使えるようになっても性能的に問題があったりと、
いろいろあって昔は結合を WHERE 句で書く習慣がありましたが、
現在はオラクル社の奨励でも JOIN 句となっています。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
between の方が性能良いのですね。結合の仕方についても勉強になりました。
>実際の業務においては「A以上B未満」のケースもあるので
すみません。仕様を五月雨にお伝えしてしまい申し訳ないのですが、
C.upd_dt between A.from_dt and A.to_dtに当てはまらないケースもあります。
そのケースに対応すべく、以下の条件を加えたいです。
現在有効なデータ(C.upd_dt between A.from_dt and A.to_dt)がなければ、
① C.upd_dt < A.from_dt(更新日時より未来のデータ)の名称を表示、①がなければ、
② C.upd_dt > A.to_dt(更新日時より過去のデータ)の名称を表示させる。
「なければ」という優先度をつけたSQLの問合せ方法はあるのでしょうか。

お礼日時:2015/03/12 17:51

同一コードにおいて有効期間をかぶらないように登録する前提、


ならば以下でよいかと。
前提が崩れると途端に変な結果となりますのでご注意ください。

select A.code, A.name, B.code, B.name, C.upd_dt
from C
inner join A on A.code = C.codeA and C.upd_dt between A.from_dt and A.to_dt
inner join B on B.code = C.codeB and C.upd_dt between B.from_dt and B.to_dt

ちなみに、出力したい内容の
A02 | い | B02 | え  | 2014-04-01
については、該当する有効期間が見つからないので、
条件に日付計算をする必要があるかもしれません
    • good
    • 0
この回答へのお礼

回答ありがとうございます。遅くなりすみません。
出力したい内容通りに動かすことができました。
しかし、以下の他案①~③でも同じ結果を得られました。(データのバリエーションは試してないですが)
日時比較に不等号ではなくbetweenを使う理由と、結合にinner joinを使う理由を是非教えていただけますか。

他案①日時の比較をbettweenから不等号とした場合
他案②inner join からleft outer joinを使う場合
他案③結合しない場合
SELECT A.code,A.name,B.code,B.name,C.upd_dt FROM C,A,B
WHERE A.code=C.codeA AND B.code=C.codeB
AND (以下省略。日時の比較はbetweenでも不等号でも出力できました。)

お礼日時:2015/03/12 14:27

select ... from C


inner join A on A.code = C.codeA and ...
inner join B on B.code = C.codeB and ...

になると思いますが、
質問では以下が不明確ですので、これ以上は書けません
* 更新日時に近いレコード、の判断方法
* C.更新日時 → 出力したい内容.更新日時、の変換方法
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

関連するカテゴリからQ&Aを探す