2017-07-19 46 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