回答編集履歴

1

データ構成が変わったことを受け、回答に追記しました。

2018/08/28 06:39

投稿

SE-studying-now
SE-studying-now

スコア351

answer CHANGED
@@ -5,4 +5,63 @@
5
5
  customer.連番 = changes.旧連番
6
6
  changes.変更日 = (「旧連番、旧カード番号が同じデータの中で最大の変更日」を取得するサブクエリ);
7
7
  ```
8
- サブクエリの書き方は色々とあると思うので、ご自身で考えてみて下さい。
8
+ サブクエリの書き方は色々とあると思うので、ご自身で考えてみて下さい。
9
+
10
+ ---
11
+ ↓↓↓追記↓↓↓
12
+ sazi様の回答にあるようにWITH RECURSIVEを使用する方法で解決できそうです。
13
+ ```SQL
14
+ WITH RECURSIVE OKYAKUSAMA AS (
15
+ SELECT '0001' AS ID, 1 AS RENNBANN, '0001001' AS CARDNO
16
+ UNION
17
+ SELECT '0001' AS ID, 3 AS RENNBANN, '0001001' AS CARDNO
18
+ UNION
19
+ SELECT '0005' AS ID, 4 AS RENNBANN, '0001010' AS CARDNO
20
+ )
21
+ , HENNKOU AS (
22
+ SELECT '1001' AS ID, 1 AS RENNBANN, '1001003' AS CARDNO, '1001' AS KYUUID, 2 AS KYUURENNBANN, '1001003' AS KYUUCARDNO, TO_TIMESTAMP('2018/08/20 12:00:00', 'YYYY/MM/DD HH24:MI:SS') AS HENKOUBI
23
+ UNION
24
+ SELECT '1001' AS ID, 2 AS RENNBANN, '1001003' AS CARDNO, '0001' AS KYUUID, 3 AS KYUURENNBANN, '0001001' AS KYUUCARDNO, TO_TIMESTAMP('2018/08/01 11:00:00', 'YYYY/MM/DD HH24:MI:SS') AS HENKOUBI
25
+ UNION
26
+ SELECT '1005' AS ID, 5 AS RENNBANN, '1001005' AS CARDNO, '0005' AS KYUUID, 4 AS KYUURENNBANN, '0001010' AS KYUUCARDNO, TO_TIMESTAMP('2018/08/20 13:00:00', 'YYYY/MM/DD HH24:MI:SS') AS HENKOUBI
27
+ )
28
+ , TAISYO(ID, RENNBANN, CARDNO, MOTOID, MOTORENNBANN, MOTOCARDNO, DEPTH) AS (
29
+ SELECT CHANGES.ID, CHANGES.RENNBANN, CHANGES.CARDNO, CUSTOMER.ID AS MOTOID, CUSTOMER.RENNBANN AS MOTORENNBANN, CUSTOMER.CARDNO AS MOTOCARDNO, 1 AS DEPTH
30
+ FROM OKYAKUSAMA AS CUSTOMER
31
+ INNER JOIN HENNKOU AS CHANGES
32
+ ON CUSTOMER.ID = CHANGES.KYUUID
33
+ AND CUSTOMER.RENNBANN = CHANGES.KYUURENNBANN
34
+ AND CUSTOMER.CARDNO = CHANGES.KYUUCARDNO
35
+ UNION ALL
36
+ SELECT CHANGES.ID, CHANGES.RENNBANN, CHANGES.CARDNO, TAISYO.MOTOID, TAISYO.MOTORENNBANN, TAISYO.MOTOCARDNO, DEPTH + 1
37
+ FROM HENNKOU AS CHANGES, TAISYO
38
+ WHERE TAISYO.ID = CHANGES.KYUUID
39
+ AND TAISYO.RENNBANN = CHANGES.KYUURENNBANN
40
+ AND TAISYO.CARDNO = CHANGES.KYUUCARDNO
41
+ )
42
+ SELECT SUB_TAISYO.ID, SUB_TAISYO.RENNBANN, SUB_TAISYO.CARDNO
43
+ FROM OKYAKUSAMA, (
44
+ SELECT SUB.*
45
+ FROM (SELECT TAISYO.*, MAX(TAISYO.DEPTH) OVER(PARTITION BY TAISYO.MOTOID, TAISYO.MOTORENNBANN, TAISYO.MOTOCARDNO) MAX_DEPTH FROM TAISYO) SUB
46
+ WHERE SUB.DEPTH = SUB.MAX_DEPTH
47
+ ) SUB_TAISYO
48
+ WHERE OKYAKUSAMA.ID = SUB_TAISYO.MOTOID
49
+ AND OKYAKUSAMA.RENNBANN = SUB_TAISYO.MOTORENNBANN
50
+ AND OKYAKUSAMA.CARDNO = SUB_TAISYO.MOTOCARDNO
51
+ ```
52
+
53
+ WITH句のOKYAKUSAMAとHENNKOUはお客様TBLと変更情報TBLをインラインで表現しているだけなので読み飛ばして下さい。(当方の環境にテーブル作成するのが面倒であったので了承下さい。。)
54
+ TAISYOの部分がWITH RECURSIVEの構文を使用している部分です。
55
+ まず、非再帰的表現部分でお客様TBLのキーと変更情報TBLの旧キーが同じデータを抽出しています。ここで、お客様情報のキーを元キー(MOTOID, MOTORENNBANN, MOTOCARDNO)として保持しています。さらに、深さを表すDEPTHを1として定義しています。
56
+ 再帰的表現部分では、非再帰的表現部分で取得できた結果の変更情報TBLのキーが変更情報TBLの旧キーと同じデータを抽出しており、これを繰り返します。繰り返すたびDEPTHは加算されます。
57
+ その結果は以下のようになります。
58
+ ```SQLの結果
59
+ ID;RENNBANN;CARDNO;MOTOID;MOTORENNBANN;MOTOCARDNO;DEPTH
60
+ "1001";2;"1001003";"0001";3;"0001001";1
61
+ "1001";1;"1001003";"0001";3;"0001001";2
62
+ "1005";5;"1001005";"0005";4;"0001010";1
63
+ ```
64
+ WITH以降のSELECT句でこの結果から**お客様TBLのキーと元キーが同じ、かつ、深さが最大のデータ**を取得すると更新対象とその更新値が取得できます。
65
+
66
+ 他にもやり方はあるかと思いますが、私のつたないSQLではこれが限界でした。。。
67
+ わかりづらい部分が多いと思いますし、やり方はこれだけではないはずなので、ご自身に合った方法を見つけて課題解決下さい。