属于特定时间段的前几行中的列值之和,并共享唯一的标识符

时间:2019-07-15 11:40:23

标签: sql oracle

我有一个表,其中包含以下列:DATE,INDIVIDUAL_ID,CONDITION_FLAG。每行代表一个特定日期的一个人。每个人都可以出现在多个日期实例上。对于条件不满足,CONDITION_FLAG可以为0,对于条件满足,可以为1。

对于该行的INDIVIDUAL_ID,我想计算CONDITION_FLAG列中1的个数,该数字发生在该行的日期与该日期之前的60天(含该日期)之间。

请参见以下示例:

SELECT DATE
  , INDIVIDUAL_ID
  , CONDITION_FLAG

FROM ORIGINAL_TABLE
;

-- ORIGINAL TABLE:
---------------------------------------------
 DATE       INDIVIDUAL_ID    CONDITION_FLAG
---------------------------------------------
 15/07/19              01               0
 12/07/19              01               1
 01/07/19              01               1
 30/06/19              01               1
 15/07/19              02               1
 11/07/19              02               0
 29/06/19              02               1
 14/07/19              03               0
 02/07/19              03               1
 30/06/19              03               0
 28/06/19              01               0
---------------------------------------------

要创建如下所示的PREV_CONDITION_COUNT列,我必须在上面的查询中添加些什么?

-- DESIRED TABLE:
---------------------------------------------------------------------
 DATE       INDIVIDUAL_ID    CONDITION_FLAG    PREV_CONDITION_COUNT 
---------------------------------------------------------------------
 15/07/19              01               0                         3
 12/07/19              01               1                         3
 01/07/19              01               1                         2
 30/06/19              01               1                         1
 15/07/19              02               1                         2
 11/07/19              02               0                         1
 29/06/19              02               1                         1
 14/07/19              03               0                         1
 02/07/19              03               1                         1
 30/06/19              03               0                         0
 28/06/19              01               0                         0
---------------------------------------------------------------------

感谢所有帮助。谢谢!

3 个答案:

答案 0 :(得分:2)

您可以使用窗口化分析功能在单个表扫描中执行此操作(无需任何联接或需要相关子查询):

Oracle设置

CREATE TABLE ORIGINAL_TABLE (DATE1, INDIVIDUAL_ID, CONDITION_FLAG ) AS
  SELECT DATE '2019-07-15', '01', 0 FROM DUAL UNION ALL
  SELECT DATE '2019-07-12', '01', 1 FROM DUAL UNION ALL
  SELECT DATE '2019-07-01', '01', 1 FROM DUAL UNION ALL
  SELECT DATE '2019-06-30', '01', 1 FROM DUAL UNION ALL
  SELECT DATE '2019-07-15', '02', 1 FROM DUAL UNION ALL
  SELECT DATE '2019-07-11', '02', 0 FROM DUAL UNION ALL
  SELECT DATE '2019-06-29', '02', 1 FROM DUAL UNION ALL
  SELECT DATE '2019-07-14', '03', 0 FROM DUAL UNION ALL
  SELECT DATE '2019-07-02', '03', 1 FROM DUAL UNION ALL
  SELECT DATE '2019-06-30', '03', 0 FROM DUAL UNION ALL
  SELECT DATE '2019-06-28', '01', 0 FROM DUAL

查询

SELECT t.*,
       SUM( CONDITION_FLAG ) OVER (
         PARTITION BY INDIVIDUAL_ID
         ORDER BY DATE1
         RANGE BETWEEN 60 PRECEDING AND 0 PRECEDING
       ) PREV_CONDITION_COUNT
FROM   ORIGINAL_TABLE t
ORDER BY INDIVIDUAL_ID, DATE1 DESC

输出

DATE1     | INDIVIDUAL_ID | CONDITION_FLAG | PREV_CONDITION_COUNT
:-------- | :------------ | -------------: | -------------------:
15-JUL-19 | 01            |              0 |                    3
12-JUL-19 | 01            |              1 |                    3
01-JUL-19 | 01            |              1 |                    2
30-JUN-19 | 01            |              1 |                    1
28-JUN-19 | 01            |              0 |                    0
15-JUL-19 | 02            |              1 |                    2
11-JUL-19 | 02            |              0 |                    1
29-JUN-19 | 02            |              1 |                    1
14-JUL-19 | 03            |              0 |                    1
02-JUL-19 | 03            |              1 |                    1
30-JUN-19 | 03            |              0 |                    0

db <>提琴here

答案 1 :(得分:1)

您可以使用以下自我联接:

SELECT
    OT1.DATE1,
    OT1.INDIVIDUAL_ID,
    OT1.CONDITION_FLAG,
    SUM(CASE
        WHEN OT2.DATE1 BETWEEN OT1.DATE1 - 60 AND OT1.DATE1 THEN OT2.CONDITION_FLAG
    END) AS P
FROM
    ORIGINAL_TABLE OT1
    JOIN ORIGINAL_TABLE OT2 ON ( OT1.INDIVIDUAL_ID = OT2.INDIVIDUAL_ID )
GROUP BY
    OT1.DATE1,
    OT1.INDIVIDUAL_ID,
    OT1.CONDITION_FLAG;

db<>fiddle demo

-在演示中,您可以忽略ID列,因为它只是用于按问题中定义的顺序为您提供输出

干杯!

答案 2 :(得分:1)

另一个选择:相关子查询:

SQL> with test (cdate, individual_id, conditional_flag) as
  2    (select date '2019-07-15', '01', 0 from dual union all
  3     select date '2019-07-12', '01', 1 from dual union all
  4     select date '2019-07-01', '01', 1 from dual union all
  5     select date '2019-06-30', '01', 1 from dual union all
  6     --
  7     select date '2019-07-15', '02', 1 from dual union all
  8     select date '2019-07-11', '02', 0 from dual union all
  9     select date '2019-06-29', '02', 1 from dual union all
 10     --
 11     select date '2019-07-14', '03', 0 from dual union all
 12     select date '2019-07-02', '03', 1 from dual union all
 13     select date '2019-06-30', '03', 0 from dual union all
 14     --
 15     select date '2019-06-28', '01', 0 from dual
 16    )
 17  select t.cdate,
 18         t.individual_id,
 19         t.conditional_flag,
 20         --
 21         (select count(*)
 22          from test t1
 23          where t1.individual_id = t.individual_id
 24            and t1.conditional_flag = 1
 25            and t1.cdate between t.cdate - 60 and t.cdate
 26         ) prev_condition_count
 27   from test t
 28  order by t.individual_id,
 29           t.cdate desc;

CDATE      IN CONDITIONAL_FLAG PREV_CONDITION_COUNT
---------- -- ---------------- --------------------
15/07/2019 01                0                    3
12/07/2019 01                1                    3
01/07/2019 01                1                    2
30/06/2019 01                1                    1
28/06/2019 01                0                    0
15/07/2019 02                1                    2
11/07/2019 02                0                    1
29/06/2019 02                1                    1
14/07/2019 03                0                    1
02/07/2019 03                1                    1
30/06/2019 03                0                    0

11 rows selected.

SQL>