简体   繁体   English

Postgres:将连续行转换为离散行

[英]Postgres: Transform Continous Rows Into a Discrete Rows

I'm not sure wether the title is correct.我不确定标题是否正确。 I've spent some time to find the best title suited for this case.我花了一些时间来找到最适合这种情况的标题。

Let say.说吧。 I have data in this format:我有这种格式的数据:

| id | room |     changes      |   created_at    |
|----|------|------------------|-----------------|
|  1 | A    | [free, occupied] | 2021-11-1 18:00 |
|  2 | B    | [free, occupied] | 2021-11-1 20:30 |
|  3 | B    | [occupied, free] | 2021-11-1 23:30 |
|  4 | A    | [occupied, free] | 2021-11-2 00:15 |
|  5 | B    | [free, occupied] | 2021-11-2 01:00 |

The output required will be所需的 output 将是

+----+------+----------+-----------------+
| id | room | occupied |   Period        |
+----+------+----------+-----------------+
|  1 | A    | NO       | 2021-11-1 18:00 |
|  2 | B    | NO       | 2021-11-1 18:00 |
|  3 | A    | NO       | 2021-11-1 19:00 |
|  4 | B    | NO       | 2021-11-1 19:00 |
|  5 | A    | YES      | 2021-11-1 20:00 |
|  6 | B    | NO       | 2021-11-1 20:00 |
|  7 | A    | YES      | 2021-11-1 21:00 |
|  8 | B    | NO       | 2021-11-1 21:00 |
|  9 | A    | YES      | 2021-11-1 22:00 |
| 10 | B    | NO       | 2021-11-1 22:00 |
| 11 | A    | YES      | 2021-11-1 23:00 |
| 12 | B    | YES      | 2021-11-1 23:00 |
| 13 | A    | YES      | 2021-11-2 00:00 |
| 14 | B    | YES      | 2021-11-2 00:00 |
| 15 | A    | NO       | 2021-11-2 01:00 |
| 16 | B    | YES      | 2021-11-2 01:00 |
| 17 | A    | NO       | 2021-11-2 02:00 |
| 18 | B    | YES      | 2021-11-2 02:00 |
+----+------+----------+-----------------+

The output generated using this logic:使用此逻辑生成的 output:

  • When during that period.那段时间的时候。 the room is changed to occupied Occupied will be "YES"房间更改为已占用 占用将是“YES”
  • when during that period.在那段时间的时候。 no changes, the change is taken from the previous change没有变化,变化取自之前的变化
  • When during that period.那段时间的时候。 the room is changed from occupied to free.房间由占用变为空闲。 The next period occupied will be "NO"下一个被占用的时间段将是“NO”

First some comments about your question:首先对您的问题发表一些评论:

  • some period values in your output doesn't correspond to the created_at values in your table output 中的某些期间值与表中的created_at值不对应
  • the id column in your output doesn't relate to the id column in your table because half of the output rows don't correspond to a row in your table, ie their id value can't be determined output 中的id列与表中的id列无关,因为 output 行的一半与表中的行不对应,即无法确定它们的id
  • the occupied value for the first period value in your output can be set up for the associated room (A) in your table but not for the others (B), so here an arbitrary value must be set up output 中第一个期间值的占用值可以为您表中的关联房间(A)设置,但不能为其他房间(B)设置,因此此处必须设置任意值

Then I propose you a query which implements the following rules:然后我建议您执行以下规则的查询:

  • When the room is changed to occupied , then occupied = "YES" for period = created_at房间更改为占用时,则占用= "YES" for period = created_at
  • when no change, ie the row doesn't exist in your_table for the given (room, period) of your output, the occupied value is copied from the previous rows with the same room and the most recent created_at value当没有变化时,即您的 output 的给定(房间,期间)中的行不存在于your_table中,占用的值是从具有相同房间和最新created_at值的先前行复制的
  • When the room is changed to free , then occupied = "NO" for period = created_at当房间更改为free时,则占用= "NO" for period = created_at

This query may provide a result slightly different from your expectation, but it can be easily adjusted.此查询提供的结果可能与您的预期略有不同,但可以轻松调整。

see the SQLfiddleSQLfiddle

SELECT t.id -- may be NULL according to the LEFT JOIN and this is a gap with the expected result as presented in the question
     , r.room
     , CASE
         WHEN t.room = r.room AND t.changes = '[free, occupied]'
         THEN 'YES'
         WHEN t.room = r.room AND t.changes = '[occupied, free]'
         THEN 'NO'
         WHEN ( jsonb_agg(t.changes)
                         FILTER (WHERE t.room = r.room)
                         OVER (PARTITION BY r.room ORDER BY p.created_at ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
              )->>-1 IS NOT DISTINCT FROM '[free, occupied]'
         THEN 'YES'
         ELSE 'NO'
       END AS occupied
     , p.created_at AS period
  FROM 
     ( SELECT DISTINCT ON (created_at) created_at
         FROM your_table
     ) AS p
 CROSS JOIN
     ( SELECT DISTINCT ON (room) room
         FROM your_table
     ) AS r
  LEFT JOIN your_table AS t
    ON t.room = r.room
   AND t.created_at = p.created_at
 ORDER BY p.created_at, r.room

In the result, the id column corresponds to the id value in your_table .结果, id列对应于your_table中的id值。 So this id is NULL when the output row doesn't correspond to any rows in your_table .因此,当 output 行与 your_table 中的任何行都不对应时,此idNULL

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM