使用窗口函数确定PostgreSQL中的30天运行计数

时间:2018-02-13 00:05:43

标签: sql postgresql

我有下表(称为row_id session_id date_end user_id item_id --------------------------------------------------- 3962 5958255 2017-11-07 3249480 1 4553 5959689 2017-11-07 3249484 1 4554 5959689 2017-11-07 3249484 1 8775 5968439 2017-11-08 3249492 4 6706 5965190 2017-11-08 3249492 2 6779 5965280 2017-11-08 3249492 3 6778 5965280 2017-11-08 3249492 3 8774 5968439 2017-11-08 3249492 4 6685 5965159 2017-11-08 3249502 1 5314 5962257 2017-11-07 3249504 1 5315 5962257 2017-11-07 3249504 1 13564 5982665 2017-11-09 3249510 1 13565 5982665 2017-11-09 3249510 1 238 5941818 2017-11-06 3249540 1 8078 5967039 2017-11-08 3249540 3 13981 5984747 2017-11-09 3249540 4 127080 6267047 2017-11-30 3249540 10 ):

item_id

查询此数据库时,我需要3个新列:

  • 每个用户购买的商品数量
  • 购买的商品数量相同 item_id作为当前行
  • 与当前行中包含不同 user_id 3249492的商品计数

但是,我需要在30天内完成所有这些计数。例如,row_id session_id date_end user_id item_id total same diff 8775 5968439 2017-11-08 3249492 4 5 1 3 6706 5965190 2017-11-08 3249492 2 4 0 3 6779 5965280 2017-11-08 3249492 3 3 1 1 6778 5965280 2017-11-08 3249492 3 2 0 1 8774 5968439 2017-11-08 3249492 4 1 0 0 的行应为:

SELECT row_id, session_id, date_end, user_id, item_id,
   COUNT(item_id) OVER (PARTITION BY user_id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) as total,
   COUNT(item_id) OVER (PARTITION BY user_id, item_id ORDER BY item_id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) as same
FROM table1

我有以下内容:

total

这会产生samediff的正确值,但不会考虑30天的窗口。另外,我不知道从哪个@Component({ selector: "protocol-details", providers: [PatientsService], template: ` <div *ngIf="data == null ;then content else table_content"></div> <ng-template #content> No Accruals </ng-template> <ng-template #table_content> <div class="container"> <div class="center"> <h3 style="color:#215081;"> Protocol Accrual for {{mdg}} for Protocol No. {{protocolNumber}}</h3> </div> <br> <div class="form-group"> <div style="position:relative"> <div class="input-group" daterangepicker (selected)="selectedDate($event, mainInput)" (cancelDaterangepicker)="calendarEventsHandler($event)" (applyDaterangepicker)="calendarEventsHandler($event)" (hideDaterangepicker)="calendarEventsHandler($event)" (showDaterangepicker)="calendarEventsHandler($event)" > <span class="form-control uneditable-input" name="daterange" > {{ mainInput.start | date:'M/dd/y' }} - {{ mainInput.end| date:'M/dd/y' }} </span> <span class="input-group-btn"> <a type="button" class="btn btn-default"><span class="glyphicon glyphicon-calendar"></span></a> </span> </div> </div> </div> </ng-template> 列开始。

SQL小提琴:http://sqlfiddle.com/#!17/ac833/2

这个PostgreSQL 9.6

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

30天运行计数

我们可以使用自联接来获取30天的运行计数,而不是使用窗口函数。

WITH thirty_days_window AS (
   SELECT table1.row_id, table1.item_id, "window".item_id AS other_item_id
   FROM table1 join table1 AS "window" ON "window".user_id = table1.user_id AND
      "window".date_end BETWEEN table1.date_end - interval '30 days' AND table1.date_end AND
      "window".row_id <= table1.row_id
),
counts AS (
   SELECT row_id,
          COUNT(*) AS total,
          COUNT(CASE WHEN item_id = other_item_id THEN 1 END) - 1 AS same,
          COUNT(CASE WHEN item_id != other_item_id THEN 1 END) AS diff
   FROM thirty_days_window GROUP BY row_id)
SELECT table1.row_id, session_id, date_end, user_id, table1.item_id,
       total, same, diff
FROM table1 JOIN counts ON counts.row_id = table1.row_id
ORDER BY row_id;

第一部分thirty_days_window通过在30天的时间内将每一行与所有具有相同user_id的行连接在一起来创建窗口。我们还假设我们只希望row_id比当前值低的行。

接下来,我们对行进行计数。 same仅计算item_id与连接行的item_id相同的行(减去1以删除原始行),diff的作用恰好相反,得到item_id与加入的行不同的所有行。

最后,我们重新加入原始表以添加session_id user_iddate_end

使用小提琴中的数据得出的最终结果:

 row_id | session_id |  date_end  | user_id | item_id | total | same | diff 
--------+------------+------------+---------+---------+-------+------+------
   6706 |    5965190 | 2017-11-08 | 3249492 |     151 |     1 |    0 |    0
   6778 |    5965280 | 2017-11-08 | 3249492 |     151 |     2 |    1 |    0
   6779 |    5965280 | 2017-11-08 | 3249492 |     158 |     3 |    0 |    2
   8774 |    5968439 | 2017-11-08 | 3249492 |     151 |     4 |    2 |    1
   8775 |    5968439 | 2017-11-08 | 3249492 |     158 |     5 |    1 |    3
  47046 |    6063745 | 2017-11-15 | 3263305 |     157 |     1 |    0 |    0
  47047 |    6063745 | 2017-11-15 | 3263305 |     158 |     2 |    0 |    1
  59887 |    6094293 | 2017-11-16 | 3263305 |     157 |     3 |    1 |    1
  59888 |    6094294 | 2017-11-16 | 3263305 |     157 |     4 |    2 |    1
  60343 |    6095456 | 2017-11-16 | 3263305 |     157 |     5 |    3 |    1
  60344 |    6095457 | 2017-11-16 | 3263305 |     157 |     6 |    4 |    1
  69112 |    6116357 | 2017-11-17 | 3263305 |     157 |     7 |    5 |    1
  71085 |    6119700 | 2017-11-18 | 3263305 |     157 |     8 |    6 |    1
  71508 |    6120421 | 2017-11-18 | 3250078 |     157 |     1 |    0 |    0
  71509 |    6120421 | 2017-11-18 | 3250078 |     152 |     2 |    0 |    1
  71510 |    6120421 | 2017-11-18 | 3250078 |     156 |     3 |    0 |    2
  71511 |    6120421 | 2017-11-18 | 3250078 |     154 |     4 |    0 |    3
  71512 |    6120421 | 2017-11-18 | 3250078 |     151 |     5 |    0 |    4
  71513 |    6120421 | 2017-11-18 | 3250078 |     158 |     6 |    0 |    5
  72242 |    6121399 | 2017-11-18 | 3263305 |     157 |     9 |    7 |    1
  75696 |    6126280 | 2017-11-19 | 3263305 |     157 |    10 |    8 |    1
  76082 |    6126777 | 2017-11-19 | 3263305 |     157 |    11 |    9 |    1
  77546 |    6129039 | 2017-11-19 | 3263305 |     157 |    12 |   10 |    1
  83754 |    6143858 | 2017-11-20 | 3263305 |     157 |    13 |   11 |    1
  91331 |    6167552 | 2017-11-22 | 3263305 |     157 |    14 |   12 |    1
  92431 |    6171560 | 2017-11-22 | 3263305 |     157 |    15 |   13 |    1
  95073 |    6177870 | 2017-11-23 | 3263305 |     157 |    16 |   14 |    1
  95302 |    6178780 | 2017-11-23 | 3263305 |     157 |    17 |   15 |    1
 287471 |    7164221 | 2018-02-10 | 4516965 |     154 |     1 |    0 |    0
 288750 |    7170955 | 2018-02-11 | 4516965 |     158 |     2 |    0 |    1
 288751 |    7170955 | 2018-02-11 | 4516965 |     151 |     3 |    0 |    2
(31 rows)

编辑

稍作考虑后,可以一次选择查询:

SELECT table1.row_id, MIN(table1.session_id),
   MIN(table1.date_end), MIN(table1.user_id), MIN(table1.item_id),
   COUNT(*) as total,
   COUNT(CASE WHEN table1.item_id = windw.item_id THEN 1 END) - 1 AS same,
   COUNT(CASE WHEN table1.item_id != windw.item_id THEN 1 END)
FROM table1 JOIN table1 AS windw ON windw.user_id = table1.user_id AND
   windw.date_end BETWEEN table1.date_end - INTERVAL '30 days' AND table1.date_end AND
   windw.row_id <= table1.row_id
GROUP BY table1.row_id ORDER BY table1.row_id;