我们有一个系统可以监控表格中记录的字段更改,我们会调用历史记录。在这种情况下,我专注于一个字段的状态和另一个字段提供的日期值。
每次保存记录时,都会创建一个新行,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
的值。
唯一的问题是,这可以通过以下三种方式之一发生:
status_dt
"首先输入字段,保存记录,然后输入" status
"输入,然后保存记录。status_dt
"首先输入字段,保存记录,然后输入" status_dt
"输入,然后保存记录。status
"字段和" status
"同时输入,然后保存记录。此外,有可能是" 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"的状态,给定可能这些字段可以填充三种方式吗?
提前致谢...
答案 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