【问题标题】:Merge hourly prices history to daily将每小时价格历史合并到每日
【发布时间】:2015-07-28 18:59:45
【问题描述】:

数据库如下:

ID | volume | timestamp (timestamp without time zone)
 1 | 300    | 2015-05-27 00:
 1 | 250    | 2015-05-28 00:
 2 | 13     | 2015-05-25 00:
 1 | 500    | 2015-06-28 22:
 1 | 100    | 2015-06-28 23:
 2 | 11     | 2015-06-28 21:
 2 | 15     | 2015-06-28 23:

有没有办法将 1 个月以前的每小时价格历史合并到每天并将它们放回表中?这意味着将每小时记录合并为 1 条记录,总数量和时间戳为 00 小时(我的意思是只有一天,2013-08-15 00:00:00)。

所以,想要的结果:

ID | volume | timestamp
 1 | 300    | 2015-05-27 00:
 1 | 250    | 2015-05-28 00:
 2 | 13     | 2015-05-25 00:
 1 | 600    | 2015-06-28 00:
 2 | 26     | 2015-06-28 00:

【问题讨论】:

  • 不清楚您在问什么。请更明确地描述您遇到的问题。
  • 对不起,我不太适合。合并=添加?哪个到什么?请理解,这里的大多数人都没有小时价格,更不想将它们合并到历史记录中。
  • 您能提供所需的输出吗?时间戳真的是28.07.2015 22: 还是类似28.07.2015 22:00:00 的东西?
  • @Pholochtairze,是的,是小时,没有分秒。

标签: sql postgresql


【解决方案1】:

看起来像一个简单的基于日期而不是时间的分组:

select id,
       sum(volume) as volume, 
       timestamp::date as timestamp
from the_table
group by id, timestamp::date
order by id, timestamp::date;

timestamp::date 会将名为timestamp(顺便说一句是列的可怕名称)的列转换为date,从而删除时间戳的时间部分(数据类型) .

timestamp::date 是 Postgres 特有的。 ANSI SQL 等效项是 cast(timestamp as date)(我是否提到 timestamp 是一个可怕的列名称?)

【讨论】:

  • 无名马,我试着把我的问题说清楚。我想在表格中进行此更改,而不是选择。
  • 感谢您的帮助。如果您想查看,我将我的最终查询作为答案发布。
【解决方案2】:

由于你想用这个新数据修改表,我想到了一个 select into。以下是我的做法(请参阅sql fiddle here):

  1. 选择所需数据并将其插入临时表 (foo_temp)
  2. 清空您的第一个表 (foo)
  3. 将临时表中的数据复制到(现在)空表中(从 foo_temp 到 foo)
  4. 删除临时表

代码如下:

/*Step 1 : Select the data you need and insert it in a temporary table*/
SELECT 
    ID,
    SUM(volume) as volume, 
    timestamp_field::date
INTO foo_temp
FROM foo
GROUP BY 
    ID,
    timestamp_field::date
ORDER BY 
    ID,
    timestamp_field::date;

/*Step 2 : Delete data from the table*/
DELETE FROM foo;

/*Step3 : Take data from the temporary table and insert it into the "main" table*/
INSERT INTO foo(ID,volume,timestamp_field)
SELECT * FROM foo_temp;

/*Step 4: Drop the temporary table*/
DROP TABLE foo_temp;

/*Step 5 : Yeah it works !*/
SELECT * FROM foo;

我必须承认@a_horse_with_no_name 完成了大部分工作,他的回答很优雅。

注意:可能有更好的方法来完成这项工作。

【讨论】:

  • 感谢您的帮助。如果您想查看,我将我的最终查询作为答案发布。
【解决方案3】:

感谢@Pholochtairze 和@a_horse_with_no_name 的帮助。
最终查询:

WITH merged_history AS (
    SELECT item_id, SUM(history_volume) AS history_volume,
        (SUM(history_medianprice * history_volume) / SUM(history_volume)) AS history_medianprice,
        history_timestamp::date
    FROM prices_history
    WHERE history_timestamp < NOW()::date - INTERVAL '1 month'
    GROUP BY item_id, history_timestamp::date),
upsert AS ( 
    UPDATE prices_history AS h
    SET history_volume = mh.history_volume, history_medianprice = mh.history_medianprice
    FROM merged_history AS mh
    WHERE h.item_id = mh.item_id AND h.history_timestamp = mh.history_timestamp RETURNING h.*)
INSERT INTO prices_history
SELECT item_id, history_volume, history_medianprice, history_timestamp
FROM merged_history
WHERE NOT EXISTS (
    SELECT 1 FROM upsert AS u, merged_history AS mh
    WHERE u.item_id = mh.item_id AND u.history_timestamp = mh.history_timestamp);

DELETE FROM prices_history
WHERE history_timestamp != history_timestamp::date
    AND history_timestamp < NOW()::date - INTERVAL '1 month';

(完成这个挑战需要2分钟(3m行):D我会每周运行一次。稍后会稍微修改一下,因为不需要合并已经合并的数据)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多