在满足某些字段条件时获取日期时间值

时间:2017-07-19 01:31:25

标签: sql datetime

我们有一个系统可以监控表格中记录的字段更改,我们会调用历史记录。在这种情况下,我专注于一个字段的状态和另一个字段提供的日期值。

每次保存记录时,都会创建一个新行,hist_id(PK)和trans_dt(SK)创建record_id(SK),以及{{1}如果字段是文本字段,则field_id确定字段的值,而如果字段是日期时间字段,则field_text提供日期时间值。每个保存仅记录所做的增量,而不记录整个记录。

随着时间的推移,用户可以更新我们呼叫的字段的记录" field_dt" (field_id = 1),其中一种状态为" A" " B" ,或者根本没有。他们还可以更新名为" status"的字段。 (field_id = 2)具有特定日期时间。

我试图确定" status_dt"的第一个点。字段定义为状态 A 和" status"字段用日期定义...并在该时间点吐出status_dt的值。

唯一的问题是,这可以通过以下三种方式之一发生:

  1. " status_dt"首先输入字段,保存记录,然后输入" status"输入,然后保存记录。
  2. " status_dt"首先输入字段,保存记录,然后输入" status_dt"输入,然后保存记录。
  3. " status"字段和" status"同时输入,然后保存记录。
  4. 此外,有可能是" status_dt"字段可以在" A"之间来回翻转。和" B&#34 ;;以及" status"的价值也可以一遍又一遍地改变。

    所以我们可能会得到这样的东西:

    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)定义为状态A和" field_id=1"字段是使用日期定义的,位于status_dt,但我们历史上会回到hist_id=7获取hist_id = 5日期(status_dt)的位置因此,当状态被重新定义为" A" ;时,两个条件都得到满足。所以代码应该返回field_id = 2

    有没有办法在第一个点查询这个日期值,其中两个字段(字段1和2)都被定义为字段1" A"的状态,给定可能这些字段可以填充三种方式吗?

    提前致谢...

2 个答案:

答案 0 :(得分:0)

  

我正在尝试确定两个“状态”字段的第一个点   用状态A定义,“status_dt”字段用a定义   date ...并在那个时间点吐出status_dt的值

但是您提供的示例数据似乎不支持这种情况,第6行是对“A”状态的唯一引用,但在第6行时或之后没有设置field_dt。

因此,我编写了以下查询,就好像您正在寻找第一次出现status =“B”一样。您可以简单地更改相关的where子句条件以适应。注意我正在使用ROW_NUMBER()because CCL documentation表示这是支持的,当与OVER()结合使用时,此功能在查找诸如“first”或“earliest”之类的逻辑时很有用(相反,对于“last”或“最新”)通过对数据进行分区和排序以适应。

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。

答案 1 :(得分: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