将每小时的价格历史合并到每日

时间:2015-07-28 18:59:46

标签: sql postgresql

数据库看起来像:

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:

3 个答案:

答案 0 :(得分:4)

根据没有时间的日期看起来像一个简单的组:

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的列(btw是列的可怕的名称)强制转换为date,从而删除时间部分时间戳(数据类型)。

timestamp::date具体是Postgres。 ANSI SQL等价物是cast(timestamp as date)(我是否提到 timestamp 是列的可怕名称?)

答案 1 :(得分:1)

由于你想用这个新数据修改表,我想到了一个select into。以下是我的进展(见sql fiddle here):

  1. 选择所需数据并将其插入临时表(foo_temp)
  2. 清空你的第一张桌子(foo)
  3. 将数据从临时表复制到(现在)空表(从foo_temp到foo)
  4. 删除临时表
  5. 以下是代码:

    /*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做了大部分工作,他的回答很优雅。

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

答案 2 :(得分:0)

感谢您的帮助@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分钟(3米行):D我将每周运行一次。稍后会稍微修改一下,因为不需要合并已合并的数据)