如何以秒的分辨率存储源数据

时间:2016-05-03 22:39:09

标签: sql postgresql timestamp forex

我有一些仅在第二个分辨率下的财务定时数据。数据本身按时间顺序排序。

Date        Time      Bid     Ask
06/07/2015  19:09:29  0.7623  0.76262
06/07/2015  19:09:29  0.7623  0.76271
06/07/2015  19:09:29  0.7623  0.76276

我希望做一些分析,要求我能够知道亚秒级。所以我最初的想法是"假的"毫秒。当在同一秒内存在多个滴答(数据点)时,我只假设它们在该秒内均匀分布。因此,由于在同一秒内有3个滴答,我假设第一个发生在第二个开始,第二个发生在.333,第三个发生在.666。

两个问题。

  1. 这种方法(伪造毫秒)是存储的最佳方式 实际订单?

  2. 我要导入相当大量的数据,所以我想我会在上传原始数据的两阶段过程中运行,然后使用选择进行毫秒计算的插入到我的目标表中。因此,对以下查询/方法的任何帮助都将不胜感激。

  3. CREATE TEMPORARY TABLE dataload (
        id serial
      , dt date
      , tm time
      , bid numeric(10,5)
      , ask numeric(10,5)
    );
    
    COPY dataload (dt, tm, bid, ask) FROM '/path/to/data.csv' WITH CSV HEADER;
    
    -- INSERT INTO actual_table
    SELECT
        dt
      , tm
      , (dt||tm)::timestamp -- Need to hack the milliseconds here
    from dataload
    group by dt, tm;
    

2 个答案:

答案 0 :(得分:1)

如果无法获得改进的数据,最好以与其背后的现实相匹配的方式对其进行建模。

所以,添加假秒可能不是一个好主意,因为你会模糊真实情况。

相反,您可以在一秒钟内添加一个订单等级的字段。这可以通过row_number() over (partition by date, time)轻松完成。

如果这有助于减少数据的大小,您可以随时将该数字转换为秒数的一部分。

答案 1 :(得分:1)

我通常不喜欢伪造数据。准确存储您给出的内容会更准确,并使用第二列来表示排序。它会花费一些额外的存储空间,但缺乏混淆可能会弥补这一点。

除非你有充分的理由,否则我也不会将时间与日期分开。

使用file_fdw代替中间表会很好,以避免额外的复制步骤。问题是file_fdw没有给你行号或任何其他排序方式,允许你使用row_number()来创建亚秒排序。所以我们需要使用一个函数。

CREATE TABLE tick(
  tick_timestamp      timestamptz      NOT NULL
  , tick_sequence     smallint         NOT NULL
  , CONSTRAINT tick__pk_tick_timestamp__tick_sequence PRIMARY KEY( tick_timestamp, tick_sequence )
  , bid               numeric(10,5)    NOT NULL
  , ask               numeric(10,5)    NOT NULL
);
CREATE FOREIGN TABLE tick_csv( tick_date date, tick_time time, bid numeric, ask numeric ) ...;
CREATE FUNCTION get_tick() RETURNS SETOF tick_csv LANGUAGE sql AS $$SELECT * FROM tick_csv$$;
COMMENT ON FUNCTION get_tick() IS $$This function is necessary because file_fdw provides no means of obtaining row numbers, which we need for safe ordering. This function allows use of WITH ORDINALITY to get a row number.$$;
INSERT INTO tick( tick_timestamp, tick_sequence, bid, ask )
  SELECT tick_timestamp
      -- Generate a series that resets for each second
      , row_number() OVER( PARTITION BY tick_timestamp ORDER BY ordinality )
      , bid
      , ask
    FROM (
      SELECT *, ( tick_date + tick_time ) AT TIME ZONE 'America/New_York' AS tick_timestamp -- CHANGE TO CORRECT TIMEZONE
        FROM get_ticks() WITH ordinality
    ) raw
;

您可能想要省略函数位并使用类似临时序列的内容来生成行号。问题在于它无法防止计划程序创建重新排序外表输出的计划。这不应该发生在简单的事情上,只是进行顺序扫描,但如果您决定加入其他表,那么您可以轻松地获得无序行。这个SQL函数安全的原因是因为它不是inlined,因为我们使用WITH ORDINALITY(因为它没有定义为STABLE,你可能会这样做)。