Sql 如何根据功率记录计算功耗?

Sql 如何根据功率记录计算功耗?,sql,postgresql,Sql,Postgresql,我有一个包含设备功率值(kW)的表格。每分钟从每个设备读取一次值,并将其插入带有时间戳的表中。我需要做的是计算给定时间跨度的功耗(kWh),并返回10个最耗电的设备。现在我查询给定时间跨度的结果,并在后端循环所有记录进行计算。这在设备数量少、时间跨度短的情况下效果很好,但在实际用例中,我可能有数千个设备和较长的时间跨度 所以我的问题是,如何在PostgreSQL 9.4.4中做到这一点,以便我的查询只返回10个最耗电的(设备id、耗电)对 示例表: CREATE TABLE measuremen

我有一个包含设备功率值(kW)的表格。每分钟从每个设备读取一次值,并将其插入带有时间戳的表中。我需要做的是计算给定时间跨度的功耗(kWh),并返回10个最耗电的设备。现在我查询给定时间跨度的结果,并在后端循环所有记录进行计算。这在设备数量少、时间跨度短的情况下效果很好,但在实际用例中,我可能有数千个设备和较长的时间跨度

所以我的问题是,如何在PostgreSQL 9.4.4中做到这一点,以便我的查询只返回10个最耗电的(设备id、耗电)对

示例表:

CREATE TABLE measurements (
  id         serial primary key,
  device_id  integer,
  power      real,
  created_at timestamp
);
简单数据示例:

| id | device_id | power |               created_at |
|----|-----------|-------|--------------------------|
|  1 |         1 |    10 | August, 26 2015 08:23:25 |
|  2 |         1 |    13 | August, 26 2015 08:24:25 |
|  3 |         1 |    12 | August, 26 2015 08:25:25 |
|  4 |         2 |   103 | August, 26 2015 08:23:25 |
|  5 |         2 |   134 | August, 26 2015 08:24:25 |
|  6 |         2 |     2 | August, 26 2015 08:25:25 |
|  7 |         3 |    10 | August, 26 2015 08:23:25 |
|  8 |         3 |    13 | August, 26 2015 08:24:25 |
|  9 |         3 |    20 | August, 26 2015 08:25:25 |
需要查询的结果:

| id | device_id | power_consumption |
|----|-----------|-------------------|
|  1 |         1 |              24.0 |
|  2 |         2 |             186.5 |
|  3 |         3 |              28.0 |
我如何计算kWh值的简化示例(以小时为单位创建):

data = [
    [
        { 'id': 1, 'device_id': 1, 'power': 10.0, 'created_at': 0 },
        { 'id': 2, 'device_id': 1, 'power': 13.0, 'created_at': 1 },
        { 'id': 3, 'device_id': 1, 'power': 12.0, 'created_at': 2 }
    ],
    [
        { 'id': 4, 'device_id': 2, 'power': 103.0, 'created_at': 0 },
        { 'id': 5, 'device_id': 2, 'power': 134.0, 'created_at': 1 },
        { 'id': 6, 'device_id': 2, 'power': 2.0, 'created_at': 2 }
    ],
    [
        { 'id': 7, 'device_id': 3, 'power': 10.0, 'created_at': 0 },
        { 'id': 8, 'device_id': 3, 'power': 13.0, 'created_at': 1 },
        { 'id': 9, 'device_id': 3, 'power': 20.0, 'created_at': 2 }
    ]
]

# device_id: power_consumption
results = { 1: 0, 2: 0, 3: 0 }

for d in data:
    for i in range(0, len(d)):
        if i < len(d)-1:
            # Area between two records gives us kWh
            # X-axis is time(h)
            # Y-axis is power(kW)
            x1 = d[i]['created_at']
            x2 = d[i+1]['created_at']
            y1 = d[i]['power']
            y2 = d[i+1]['power']
            # Area between two records gives us kWh
            # X-axis is time(h)
            # Y-axis is power(kW)
            x1 = d[i]['created_at']
            x2 = d[i+1]['created_at']
            y1 = d[i]['power']
            y2 = d[i+1]['power']

            results[d[i]['device_id']] += ((x2-x1)*(y2+y1))/2

print results
数据=[
[
{'id':1,'device_id':1,'power':10.0,'created_at':0},
{'id':2,'device_id':1,'power':13.0,'created_at':1},
{'id':3,'device_id':1,'power':12.0,'created_at':2}
],
[
{'id':4,'device_id':2,'power':103.0,'created_at':0},
{'id':5,'device_id':2,'power':134.0,'created_at':1},
{'id':6,'device_id':2,'power':2.0,'created_at':2}
],
[
{'id':7,'device_id':3,'power':10.0,'created_at':0},
{'id':8,'device_id':3,'power':13.0,'created_at':1},
{'id':9,'device_id':3,'power':20.0,'created_at':2}
]
]
#设备id:功耗
结果={1:0,2:0,3:0}
对于数据中的d:
对于范围(0,len(d))中的i:
如果i

编辑:查看我是如何解决此问题的。

完成此操作所需的一些元素包括:

  • Sum()聚合,用于计算记录总数
  • Lag()/Lead()函数,用于计算给定记录的“上一个”或“下一个”记录的值
  • 因此,对于给定的行,您可以获取当前创建的\u at和电源记录,在SQL中,您可能会使用Lead()窗口函数来获取同一设备id的已创建的\u at和电源记录,该设备id的已创建的\u at和电源记录的值仅次于已创建的\u at

    Lead()的文档如下所示:

    当参考“下一个”记录计算每一行的功耗时,可以使用Sum()将该设备的所有计算功耗相加

    计算每个设备的功率后,可以使用ORDER BY和LIMIT选择前n个功耗设备

    如果您没有信心投入并编写最后的SQL,请遵循以下步骤——在每一步之后,确保您有您理解的SQL,并且它只返回您需要的数据:

  • 通过选择所需的数据行,从小处开始
  • 计算Lead()函数,定义适当的partition和order子句以获取下一行
  • 添加每行的功率计算
  • 定义Sum()函数,并按设备id分组
  • 添加ORDER BY和LIMIT子句

  • 如果您对这些步骤中的任何一个有问题,它们都会提出一个体面的堆栈溢出问题。

    如果有人碰巧想知道我是如何解决这个问题的。
    我按照David的指示做了如下工作:

    SELECT
      t.device_id,
      sum(len_y*(extract(epoch from date_trunc('milliseconds', len_x)))7200) AS total
    FROM (
        SELECT
          m.id,
          m.device_id,
          m.power,
          m.created_at,
          m.power+lag(m.power) OVER (
            PARTITION BY device_id
            ORDER BY m.created_at
          ) AS len_y,
          m.created_at-lag(m.created_at) OVER (
            PARTITION BY device_id
            ORDER BY m.created_at
          ) AS len_x
        FROM
          mes AS m
      WHERE m.created_at BETWEEN '2015-08-26 13:39:57.834674'::timestamp
        AND '2015-08-26 13:43:57.834674'::timestamp
    ) AS t
    GROUP BY t.device_id
    ORDER BY total
    DESC LIMIT 10;
    

    编辑:根据评论中的建议更改了计算。

    我认为您的消费量可以更简单地计算为(x2-x1)*(y1+y2)/2@DavidAldridge那是真的,谢谢!你知道抽样方法永远不会非常准确,对吧?因为它会错过尖峰负载,会受到样本定时引起的错误,等等?是的,这也是我通过阅读postgresql文档得出的结论,但我现在知道如何在一个查询中实现这一切。您可以添加一个示例吗?虽然“../60/60)/2”对程序员来说更具描述性,但您可能只想在生产中使用“../7200”,因为每行可以保存2个操作,并且可能会对非常大的数据集产生显著的影响。当然,你应该把7200的意思写在评论里。