• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:日付の前後関係で2つのテーブルを結合したい)

日付の前後関係で2つのテーブルを結合したい

このQ&Aのポイント
  • 親子関係を持つ2つのテーブルを日付の前後関係で結合するSQLについて教えてください。
  • Access2003のデータベースで、親テーブルと子テーブルを結合し、特定の条件でデータを取得したいです。
  • 契約基本テーブルと契約明細テーブルを結合する際に、契約明細の契約日と最も近い契約基本の契約日を取得したいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • 30246kiku
  • ベストアンサー率73% (370/504)
回答No.4

#2です では、以下でどうなりますか SELECT Q1.契約番号, Q1.契約種別, Q1.明細契約年月日, Q2.基本SEQ, Q2.契約者名, Q2.基本契約年月日 FROM 契約明細 AS Q1, 契約基本 AS Q2 WHERE Q2.基本SEQ = (SELECT TOP 1 基本SEQ FROM 契約基本 WHERE 契約番号=Q1.契約番号 AND 基本契約年月日<=Q1.明細契約年月日 ORDER BY 基本契約年月日 DESC, 基本SEQ DESC);

k28484
質問者

お礼

再度ご回答いただき、ありがとうございます。 期待通りの結果を得ることができました!!! 副問い合わせに関する理解が不足しているため、 上記のSQL文を理解するのに少し時間がかかりましたが、 いろいろ調べて、 なるほど! と目から鱗でした。 大変助かりました。

その他の回答 (4)

  • world99
  • ベストアンサー率64% (20/31)
回答No.5

k28484 さん 横から余計な口出しをして申し訳ありませんが、テーブル設計が正しく行われていないように思います。 そのため契約明細と契約基本のデータを結合して取得するだけなのに、とても複雑な結合条件が必要でSQL文もかなり複雑になってしまっています。 一般的に親テーブルの主キーで子テーブルのデータを検索できなければなりません。その逆もしかり。 親テーブル「契約基本」の主キーは基本SEQですが、子テーブル「契約明細」にはその基本SEQが含まれていません。 基本契約年月日と明細契約年月日の近いという条件でテーブルを結合するとデータの不整合が起こります。 例えば2人の契約者が違うが同じ契約明細年月日の場合、基本SEQの値が大きい契約基本テーブルのデータを探すと、1人の契約者名しか表示されません。 1人の契約者は1つの契約種別のデータを持たないなら、テーブルを親子に分ける必要がありません。 (契約番号を主キーに持つテーブルがあると見受けられます。契約基本テーブルはそのテーブルの子テーブルなのではないでしょうか?) ■1つのテーブルにした例 契約テーブル  主キー:基本SEQ 【基本SEQ】【契約番号】【契約者名】【基本契約年月日】【契約種別】【明細契約年月日】  1       K0001   契約者1A 2013/05/01    S1     2013/05/05  2       K0001   契約者1B 2013/05/10    S1     2013/05/10  3       K0001   契約者1C 2013/05/20    S2     2013/05/25  4       K0002   契約者2A 2013/06/10    S2     2013/06/10  5       K0002   契約者2B 2013/06/10    S1     2013/06/15  6       K0002   契約者2C 2013/06/10    S2     2013/06/10  7       K0003   契約者3A 2013/07/01    S1     2013/07/05  8       K0003   契約者3B 2013/07/10    S2     2013/07/10  9       K0003   契約者3C 2013/07/10    S1     2013/07/10 1人の契約者が複数の契約種別のテータを持つ場合、テーブルは親子に分けます。親テーブルの主キーで子テーブルのデータを検索できるように子テーブルの主キーを決めます。 ■親子にテーブルを分けた例 契約基本テーブル  主キー:基本契約番号(基本SEQ) 【基本契約番号】【契約番号】【契約者名】【基本契約年月日】  1        K0001   契約者1A 2013/05/01  2        K0001   契約者1B 2013/05/10  3        K0001   契約者1C 2013/05/20  4        K0002   契約者2A 2013/06/10  5        K0002   契約者2B 2013/06/10  6        K0002   契約者2C 2013/06/10  7        K0003   契約者3A 2013/07/01  8        K0003   契約者3B 2013/07/10  9        K0003   契約者3C 2013/07/10 契約明細テーブル  主キー:基本契約番号(基本SEQ)、明細番号 【基本契約番号】【明細番号】【契約種別】【明細契約年月日】  1        1     S1     2013/05/05  1        2     S2     2013/05/10  2        1     S1     2013/05/05  2        2     S2     2013/05/10  3        1     S1     2013/05/05  3        2     S2     2013/05/10  4        1     S1     2013/06/05  4        2     S2     2013/06/10  5        1     S1     2013/06/05  5        2     S2     2013/06/10  6        1     S1     2013/06/05  6        2     S2     2013/06/10  7        1     S1     2013/07/05  7        2     S2     2013/07/15  8        1     S1     2013/07/05  8        2     S2     2013/07/15  9        1     S1     2013/07/05  9        2     S2     2013/07/15

k28484
質問者

お礼

ご指摘ありがとうございます。 余計な口出しではございません。 大変参考になりました。 親子テーブルの契約は、法人を対象としており、 契約者名は、契約担当者名だとお考え下さい。 なので例でいうと、K001は全て同じ法人となります。 今回やりたかったのは、契約明細が締結された時点で、 その親の契約基本の内容はどうだったのか、という一覧を 得たかったのです。 いただいたご指摘は今後のテーブル設計の参考にさせて いただきます。 ありがとうございました。

  • root139
  • ベストアンサー率60% (488/809)
回答No.3

#1 です。 とりあえず、Access でも動く事は動いたようですね。 > 契約年月日の比較を優先し、1レコードに絞り込めなかった場合に基本SEQで比較したいのです。 なるほど。では、基本契約年月日が同じで基本SEQの大きなものが無いという条件に書き換えてみてはどうでしょうか。 変更したのは EXISTS() の中の WHERE 句です。 SELECT * FROM 契約明細 km INNER JOIN 契約基本 kk ON(km.契約番号 = kk.契約番号 AND kk.基本契約年月日 <= km.明細契約年月日) WHERE NOT EXISTS(SELECT * FROM 契約基本 kk2 WHERE kk2.契約番号 = km.契約番号 AND kk2.基本契約年月日 <= km.明細契約年月日 AND (kk.基本契約年月日 < kk2.基本契約年月日 OR kk.基本契約年月日 = kk2.基本契約年月日 AND kk.基本SEQ < kk2.基本SEQ)) ORDER BY 明細契約年月日;

k28484
質問者

お礼

再度ご回答いただき、ありがとうございます。 期待通りの結果を得ることができました。 EXISTS句はこれまで使ったことがなかったので 一見かなり難解なSQL文に見えたのですが、 こういう使い方があるんだな、 と大変勉強になりました。 今回いただいたご回答を参考に今後はEXSITS句も 積極的に使えるようになりたいと思います。 どうもありがとうございました。

  • 30246kiku
  • ベストアンサー率73% (370/504)
回答No.2

以下でどうなりますか SELECT Q1.契約番号, Q1.契約種別, Q1.明細契約年月日, Q2.基本SEQ, Q2.契約者名, Q2.基本契約年月日 FROM 契約明細 AS Q1, 契約基本 AS Q2 WHERE Q2.基本SEQ = (SELECT Max(基本SEQ) FROM 契約基本 WHERE 契約番号=Q1.契約番号 AND 基本契約年月日<=Q1.明細契約年月日); ※ 処理性能はわかりません

k28484
質問者

補足

ご回答ありがとうございます。 root139さんのご回答にも補足させていただいたのですが、 基本契約年月日の前後関係が逆転することがあります。 基本SEQのMAXをとってしまうと 契約明細・契約番号単位で、明細契約年月日に最も近い という条件を満たせない場合があるのです。 私の挙げた例がわかりにくくて申しわけありません。 基本契約年月日の並び順がバラバラという前提で 何か良いアイデアがございましたらご教示ください。 よろしくお願いします。

  • root139
  • ベストアンサー率60% (488/809)
回答No.1

手元に Access が無いので動作未確認ですが、下記の SQL ではどうですか? SELECT * FROM 契約明細 km INNER JOIN 契約基本 kk ON(km.契約番号 = kk.契約番号 AND kk.基本契約年月日 <= km.明細契約年月日) WHERE NOT EXISTS(SELECT * FROM 契約基本 kk2 WHERE kk2.契約番号 = km.契約番号 AND kk2.基本契約年月日 <= km.明細契約年月日 AND (kk.基本契約年月日 < kk2.基本契約年月日 OR kk.基本SEQ < kk2.基本SEQ)) ORDER BY 明細契約年月日;

参考URL:
http://codezine.jp/article/detail/460
k28484
質問者

補足

ご回答ありがとうございます。 大変勉強になりました。 私の挙げた具体例が悪く、申しわけありません。 基本契約年月日は更新可能で、前後関係が逆転する場合があります。 質問の例でK001だけに限定しますが、下記のようなパターンがありえます。 契約明細は質問の例のままとします。 親テーブル:契約基本 【基本SEQ】【契約番号】 【契約者名】【基本契約年月日】 1     K0001    契約者1A 2013/05/10 2     K0001    契約者1B 2013/05/01 3     K0001    契約者1C 2013/04/30 このような場合は、テーブル結合で下記の結果を得たいです。 【契約番号】【契約種別】【明細契約年月日】【基本SEQ】【契約者名】【基本契約年月日】 K0001    S1     2013/05/05    2     契約者1B 2013/05/01 K0001    S2     2013/05/10    1     契約者1A 2013/05/10 契約年月日の比較を優先し、1レコードに絞り込めなかった場合に基本SEQで 比較したいのです。 再度お知恵をかしていただけませんでしょうか?

関連するQ&A