2017-07-19 88 views
0

我們有一個系統監視表中記錄的字段更改,我們將其稱爲歷史記錄。在這種情況下,我專注於一個字段的狀態和另一個字段提供的日期值。當某些現場條件得到滿足時獲取日期時間值

每當一個記錄被保存在一個新的行爲,相對於record_id(SK)創建hist_id(PK)和trans_dt(SK)創建,具有field_id,確定受影響的領域一起,field_text提供現場如果值該字段是文本字段,而如果該字段是日期時間字段,則field_dt會提供日期時間值。每個保存只記錄所做的增量,而不是整個記錄。

隨着時間的推移用戶可能會更新一個字段記錄我們稱之爲「status」(FIELD_ID = 1)兩種狀態「A」「B」,或者什麼都沒有之一。他們還可能更新某個日期時間的字段「status_dt」(field_id = 2)。

我想,以確定這兩個「status」字段與狀態一個和「status_dt」字段與日期定義定義的第一點......就在那吐出的status_dt值時間點。

唯一的問題是,這可以通過以下三種方式之一發生:

  1. 的「status」場第一次進入,記錄保存,然後將「status_dt」進入,然後記錄保存。
  2. 首先輸入「status_dt」字段,保存記錄,然後輸入「status」,然後保存記錄。
  3. 同時輸入「status」字段和「status_dt」,然後保存記錄。

此外,「status」字段可以在「A」和「B」之間來回翻轉;以及「status_dt」的價值也可以一遍又一遍地改變。

所以可能我們可以得到這樣的事情:

hist_id trans_dt   record_id field_id field_text field_dt 
------- ----------------- --------- -------- ---------- ----------------- 
     1 28/11/16 11:37:56   1  3 N/A 
     2 09/12/16 11:52:51   1  4 Yes 
     3 01/01/17 12:45:17   1  2   28/02/17 00:00:00 
     4 14/07/17 09:01:58   1  1 B 
     5 14/07/17 09:01:58   1  2   01/07/17 00:00:00 
     6 14/07/17 09:01:58   1  5   31/07/17 00:00:00 
     7 14/07/17 11:11:30   1  1 A 

所以在這種情況下,在時間點裏的「status」字段(field_id=1)都與狀況的定義和「status_dt」字段日期定義爲hist_id=7,但我們歷史上會回到hist_id = 5以獲取status_dt日期(其中field_id = 2)的點,因此,在狀態重新定義爲時,兩個條件都得到滿足「 A「;所以代碼應該返回01/07/17 00:00:00

有沒有一種方法來查詢這個日期值的第一個點,其中兩個字段(字段1和2)都已定義字段1的狀態爲「A」,給定可能的三這些字段可以填充的方式?

在此先感謝...

+0

哪個[DBMS](https://en.wikipedia.org/wiki/DBMS)您使用的? Postgres的?甲骨文? –

+0

我目前使用的是借用Oracle的CCL(Cerner命令語言)。這有幫助嗎?該示例數據中的 –

+0

,「預期結果」是什麼? –

回答

0

我試圖確定在「狀態」欄都 與狀態A和「status_dt」字段定義與 日期確定的第一點...吐出status_dt的價值在那個時間點

但是您提供的示例數據似乎並不支持這種情況,第6行是對「A」狀態的唯一引用,但沒有設置field_dt或在第6行。

所以,我寫了下面的查詢,就好像你正在尋找第一個o而不是狀態=「B」。您可以簡單地修改適合的where條款條件。注意我正在使用ROW_NUMBER()because CCL documentation表明這是支持的,當與OVER()結合使用時,查找諸如「first」或「early」之類的邏輯(反過來對「last」或「latest」也是有用的)通過劃分和排序數據來適應。

CREATE TABLE HISTORY 
    ("HIST_ID" int, "TRANS_DT" date, "RECORD_ID" int, "FIELD_ID" int, "FIELD_TEXT" varchar2(4), "FIELD_DT" date); 
INSERT ALL 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (1, to_date('28/11/16 11:37:56','dd/mm/yyyy hh24:mi:ss'), 1, 3, 'N/A', NULL) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (2, to_date('09/12/16 11:52:51','dd/mm/yyyy hh24:mi:ss'), 1, 4, 'Yes', NULL) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (3, to_date('14/07/17 09:01:58','dd/mm/yyyy hh24:mi:ss'), 1, 1, 'B', NULL) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (4, to_date('14/07/17 09:01:58','dd/mm/yyyy hh24:mi:ss'), 1, 2, NULL, to_date('01/07/17 00:00:00','dd/mm/yyyy hh24:mi:ss')) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (5, to_date('14/07/17 09:01:58','dd/mm/yyyy hh24:mi:ss'), 1, 5, NULL, to_date('31/07/17 00:00:00','dd/mm/yyyy hh24:mi:ss')) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (6, to_date('14/07/17 11:11:30','dd/mm/yyyy hh24:mi:ss'), 1, 1, 'A', NULL) 
SELECT * FROM dual; 
 
6 rows affected 
 select 
      h.record_id 
      , d.trans_dt trans_dt_1 
      , h.trans_dt trans_dt_2 
      , d.field_text 
      , h.field_dt 
      , row_number() over(partition by h.record_id order by h.trans_dt ASC, h.hist_id ASC) rn 
     from history h 
     inner join (
      select 
        record_id 
       , trans_dt 
       , field_text 
       , row_number() over(partition by record_id, field_id order by trans_dt ASC) rn 
      from history 
      where field_id = 1 
      and field_text = 'B' 
     ) d on h.record_id = d.record_id and d.rn = 1 
     where h.trans_dt >= d.trans_dt 
     and h.field_id in (2,5) 
 
RECORD_ID | TRANS_DT_1 | TRANS_DT_2 | FIELD_TEXT | FIELD_DT | RN 
--------: | :--------- | :--------- | :--------- | :-------- | -: 
     1 | 14-JUL-17 | 14-JUL-17 | B   | 01-JUL-17 | 1 
     1 | 14-JUL-17 | 14-JUL-17 | B   | 31-JUL-17 | 2 
select 
     record_id 
    , trans_dt_1 
    , trans_dt_2 
    , field_text 
    , field_dt 
FROM (
     select 
      h.record_id 
      , d.trans_dt trans_dt_1 
      , h.trans_dt trans_dt_2 
      , d.field_text 
      , h.field_dt 
      , row_number() over(partition by h.record_id order by h.trans_dt ASC, h.hist_id ASC) rn 
     from history h 
     inner join (
      select 
        record_id 
       , trans_dt 
       , field_text 
       , row_number() over(partition by record_id, field_id order by trans_dt ASC) rn 
      from history 
      where field_id = 1 
      and field_text = 'B' 
     ) d on h.record_id = d.record_id and d.rn = 1 
     where h.trans_dt >= d.trans_dt 
     and h.field_id in (2,5) 
    ) d2 
where d2.rn = 1; 
 
RECORD_ID | TRANS_DT_1 | TRANS_DT_2 | FIELD_TEXT | FIELD_DT 
--------: | :--------- | :--------- | :--------- | :-------- 
     1 | 14-JUL-17 | 14-JUL-17 | B   | 01-JUL-17 

dbfiddle here

請注意SQLFiddle停止工作(再次),所以我換反而dbfiddle。

+0

偉大的方法,但讓我再添加一行到歷史數據,使其更清晰... –

+0

你可以做到這一點在sqlfiddle和測試它有鏈接上面提供,但在這裏再次http://sqlfiddle.com/#!4/9856c/9 –

+0

在使用hist_id作爲時間排序器並使用字段2和字段5時發生了變化 –

0

這種方法使用修改後的樣本數據,並且將子查詢2之間用作h.trans_dt < = d.trans_dt(字段1更改日期< =字段2變化日期)的日期的關係。這樣可以使樣本數據符合預期結果(如問題的評論中所述)。

CREATE TABLE HISTORY 
    ("HIST_ID" int, "TRANS_DT" date, "RECORD_ID" int, "FIELD_ID" int, "FIELD_TEXT" varchar2(4), "FIELD_DT" date); 
INSERT ALL 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (1, to_date('28/11/16 11:37:56','dd/mm/yyyy hh24:mi:ss'), 1, 3, 'N/A', NULL) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (2, to_date('09/12/16 11:52:51','dd/mm/yyyy hh24:mi:ss'), 1, 4, 'Yes', NULL) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (3, to_date('14/07/17 09:01:58','dd/mm/yyyy hh24:mi:ss'), 1, 1, 'B', NULL) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (4, to_date('14/07/17 09:01:58','dd/mm/yyyy hh24:mi:ss'), 1, 2, NULL, to_date('01/07/17 00:00:00','dd/mm/yyyy hh24:mi:ss')) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (5, to_date('14/07/17 09:01:58','dd/mm/yyyy hh24:mi:ss'), 1, 5, NULL, to_date('31/07/17 00:00:00','dd/mm/yyyy hh24:mi:ss')) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (6, to_date('14/07/17 11:11:30','dd/mm/yyyy hh24:mi:ss'), 1, 1, 'A', NULL) 
    INTO HISTORY ("HIST_ID", "TRANS_DT", "RECORD_ID", "FIELD_ID", "FIELD_TEXT", "FIELD_DT") 
     VALUES (7, to_date('14/07/17 11:11:30','dd/mm/yyyy hh24:mi:ss'), 1,1, 'A', NULL) 
SELECT * FROM dual; 
 
7 rows affected 
select 
     record_id 
    , trans_dt_1 
    , trans_dt_2 
    , field_text 
    , field_dt 
FROM (
     select 
      h.record_id 
      , d.trans_dt trans_dt_1 
      , h.trans_dt trans_dt_2 
      , d.field_text 
      , h.field_dt 
      , row_number() over(partition by h.record_id order by h.trans_dt ASC, h.hist_id ASC) rn 
     from history h 
     inner join (
      select 
        record_id 
       , trans_dt 
       , field_text 
       , row_number() over(partition by record_id, field_id order by trans_dt ASC) rn 
      from history 
      where field_id = 1 
      and field_text = 'A' 
     ) d on h.record_id = d.record_id and d.rn = 1 
     where h.trans_dt <= d.trans_dt 
     and h.field_id = 2 
    ) d2 
where d2.rn = 1; 
 
RECORD_ID | TRANS_DT_1 | TRANS_DT_2 | FIELD_TEXT | FIELD_DT 
--------: | :--------- | :--------- | :--------- | :-------- 
     1 | 14-JUL-17 | 14-JUL-17 | A   | 01-JUL-17 

該方法使用ROW_NUMBER(),因爲CCL文檔(here)指示其被支撐和此功能,尋找邏輯時當與OVER()合併是有益的,諸如「第一」或「最早的」(反過來也適用於「最後」或「最新」)通過劃分和排序數據來適應。

dbfiddle here

相關問題