计算数据库中每两行之间的字段 - 按实体分组 - 相同的表 - postgresql

时间:2017-04-19 14:07:04

标签: postgresql

视图中的数据如下所示:

id      time                       revs       m_id  tag_id
320518  2017-04-05 14:01:25         216210396   1   1
320620  2017-04-05 14:11:33         216217766   1   1
27346   2017-12-09 15:15:52         699         2   1
27347   2017-12-09 15:19:52         1618        2   1

目标:我需要通过执行以下操作来计算每分钟的转速:

(row2 rev- row1 rev)/ (row2 time - row1 time)=revs per minute
对于每两行。也适用于每个m_id(1和2)。换句话说,当m_id改变时 - 它将执行与该m_id相关联的行。它还需要按tag_id分组。

我需要结果数据如下所示:

time                 m_id    tag_id   time_diff     rev_diff   rpm
2017-04-05 14:11:33    1        1        10.13        7370      727.54
2017-12-09 15:15:52    2        1        4            919       229.75

有数千行。我已经将视图设置为m_id然后按时间排序的位置。

将它全部保存在同一个表/视图中的原因是因为我可以有任意数量的m_ids。我需要它是动态的,所以无论创建多少个m_id,我仍然可以确定rpms。

我原来的解决方案是为每个m_id创建过滤后的视图,但这不适用于“插入式”程序。

更新:4/20/17

我使用@Tim Biegeleisen答案作为模板(使用我的实际字段名称)调整了我的脚本。

WITH cte AS (
    SELECT
        machine_id_id,
        rfid_tag_id,
        "event_at",
        LAG("event_at") OVER (ORDER BY "event_at" PARTITION BY machine_id_id) AS prev_time, 
rev_count, LAG(rev_count) OVER (ORDER BY "event_at" PARTITION BY machine_id_id) AS prev_revs
    FROM machines_status_updates
)
SELECT t.*,
       (rev_count - tprev_revs) /
       (EXTRACT(EPOCH FROM (t.event_at - t.prev_time)) / 60) AS rpm
FROM cte t
WHERE t.prev_time IS NOT NULL

它仍在抛出语法错误 - 在第一个PARTITION BY - 但我没有看到语法错误。

错误:

sql> WITH cte AS (
    SELECT
        machine_id_id,
        rfid_tag_id,
        "event_at",
        LAG("event_at") OVER (ORDER BY "event_at" PARTITION BY machine_id_id) AS prev_time,
        rev_count,
        LAG(rev_count) OVER (ORDER BY "event_at" PARTITION BY machine_id_id) AS prev_revs
    FROM machines_status_updates
)
[2017-04-20 10:36:16] [42601] ERROR: syntax error at or near "PARTITION"
[2017-04-20 10:36:16] Position: 154

通过文档(因为这个CTE对我来说有点新鲜) - 一切看起来都对 - 我找不到我错过的东西。

为了便于查看: enter image description here

编辑(2017年4月5日更新) - 取得进展

这是脚本的最新版本(消除PARTITION Error然后除以零错误)

WITH cte AS (
    SELECT
        machine_id_id,
        rfid_tag_id,
        event_at,
        LAG(event_at) OVER (ORDER BY machine_id_id, event_at) AS prev_time,
        rev_count,
        LAG(rev_count) OVER (ORDER BY machine_id_id, event_at) AS prev_revs
    FROM machines_status_updates
)
SELECT t.*,
       (t.rev_count - t.prev_revs) / NULLIF(
       (EXTRACT(EPOCH FROM (t.event_at - t.event_at)) / 60), 0)  AS rpm
FROM cte t
WHERE t.prev_time IS NOT NULL;

数据集看起来像这样: Almost There...

RPM在整个数据集中返回NULL - 行似乎都运行良好。有什么想法吗?

最终答案: WOOOHOOOO!终于明白了! :D来自@Tim Biegeleisen的回答。

最终剧本:

WITH cte AS (
    SELECT
        machine_id_id,
        rfid_tag_id,
        event_at,
        LAG(event_at) OVER (ORDER BY machine_id_id, event_at) AS prev_time,
        rev_count,
        LAG(rev_count) OVER (ORDER BY machine_id_id, event_at) AS prev_revs
    FROM machines_status_updates
)
SELECT t.*, (t.rev_count - t.prev_revs)AS rev_diff, (EXTRACT(EPOCH FROM (t.event_at - t.prev_time)
                                                     ) / 60) AS time_diff,
       (t.rev_count - t.prev_revs) / NULLIF(
       (EXTRACT(EPOCH FROM (t.event_at - t.prev_time)) / 60), 0)  AS rpm
FROM cte t
WHERE t.prev_time IS NOT NULL;

它是null因为我从它自己减去t.event而不是prev_time。我添加了一些列,以便我可以验证rpms。

最终结果:

enter image description here

1 个答案:

答案 0 :(得分:2)

WITH cte AS (
    SELECT
        m_id,
        tag_id,
        "time",
        LAG("time") OVER (ORDER BY "time" PARTITION BY m_id) AS prev_time,
        revs,
        LAG(revs) OVER (ORDER BY "time" PARTITION BY m_id) AS prev_revs
    FROM yourTable
)
SELECT t.*,
       (t.revs - t.prev_revs) /
       (EXTRACT(EPOCH FROM (t.time - t.prev_time)) / 60) AS rpm
FROM cte t
WHERE t.prev_time IS NOT NULL