基于其他 table 创建填充 table 的触发器

A trigger to create populate a table based on other table

好吧,既然我的最后两个问题(this one and this one)似乎只会导致混乱,我会尽量在这里解释完整的问题,所以它可能会很长post。

我正在尝试为交易系统创建数据库。数据库有 2 个主要的 tables。一个是 table "Ticks",另一个是 "Candles"。如图,每个table都有自己的属性。.

蜡烛图、条形图或 ohlc 是同一回事。

蜡烛在图表中的显示方式如下:

蜡烛只是表示聚合数据的一种方式,仅此而已。

有很多方法可以聚合报价以创建一根蜡烛。在此 post 中,我要求一种每 500 个跳动点创建一个蜡烛的特定方法。所以,如果 ticks table 有 1000 个分时点,我只能创建 2 个蜡烛。如果它有 500 个刻度,我可以创建 1 个蜡烛。如果它有 5000 个刻度,我可以创建 10 个蜡烛。如果有 5001 个刻度,我仍然只有 10 个蜡烛,因为我缺少其他 499 个刻度来创建第 11 个蜡烛。

实际上,我正在使用 python 脚本存储所有报价并创建(因此,插入 candles table)蜡烛与另一个 python脚本。 这是一个实时过程

两个脚本 运行 在一个 while True: 循环中。不,我不能(阅读不应该)停止脚本,因为市场每周 5 天 24 小时开放。

我想要做的是摆脱 python 脚本,该脚本在 candles table 中创建和存储蜡烛。为什么?因为我认为它会提高性能。我认为触发器可以以更有效的方式处理它,而不是进行多次查询来了解可用于创建新蜡烛的刻度数 (如果我弄错了,请纠正我).

我不知道如何实际解决它,但我正在尝试这样做(感谢@GordonLinoff 在之前的问题中帮助我):

do $$

begin
with total_ticks as (
    select count(*) c from (
    select *  from eurusd_tick2 eurusd where date > 
        (SELECT date from eurusd_ohlc order by date desc limit 1) 
        order by date asc) totals),
        ticks_for_candles as(
        select * from eurusd_tick2 eurusd where date > 
        (SELECT date from eurusd_ohlc order by date desc limit 1) 
        order by date asc
        ), candles as(
       select max(date) as date,
       max(bid) filter (where mod(seqnum, 500) = 1) as open,
       max(bid) as high,
       min(bid) as low,
       max(bid) filter (where mod(seqnum, 500) = 500-1) as close,
       max(ask) filter (where mod(seqnum, 500) = 500-1) as ask

        from (
            select t.*, row_number() over (order by date) as seqnum
              from (select * from ticks_for_candles) t) as a

        group by floor((seqnum - 1) /500)
        having count(*) = 500
        )


case 500<(select * from total_ticks)
when true then

        return select * from candles
    end;
end $$;

使用这个,我得到这个错误:

ERROR:  syntax error at or near "case"
LINE 33: case 500<(select * from total_ticks)
         ^
SQL state: 42601
Character: 945

如您所见,CET 后没有 select。如果我输入:

select case 500<(select * from total_ticks)
    when true then

            return select * from candles
        end;
    end $$;

我收到这个错误:

ERROR:  subquery must return only one column
LINE 31:   (select * from candles)
           ^
QUERY:  with total_ticks as (
    select count(*) c from (
    select *  from eurusd_tick2 eurusd where date > 
        (SELECT date from eurusd_ohlc order by date desc limit 1) 
        order by date asc) totals),
        ticks_for_candles as(
        select * from eurusd_tick2 eurusd where date > 
        (SELECT date from eurusd_ohlc order by date desc limit 1) 
        order by date asc
        ), candles as(
       select max(date) as date,
       max(bid) filter (where mod(seqnum, 500) = 1) as open,
       max(bid) as high,
       min(bid) as low,
       max(bid) filter (where mod(seqnum, 500) = 500-1) as close,
       max(ask) filter (where mod(seqnum, 500) = 500-1) as ask

        from (
            select t.*, row_number() over (order by date) as seqnum
              from (select * from ticks_for_candles) t) as a

        group by floor((seqnum - 1) /500)
        having count(*) = 500
        )


select case 1000>(select * from total_ticks)
when true then

        (select * from candles)
    end
CONTEXT:  PL/pgSQL function inline_code_block line 4 at SQL statement
SQL state: 42601

老实说,我不知道如何正确地做到这一点。它不一定与我在此处提供的实际代码相同,但所需的输出如下所示:

-----------------------------------------------------------------------------------
|          date            |    open   |   high   |    low  |   close  |    ask   |
|2020-05-01 20:39:27.603452|    1.0976 |  1.09766 | 1.09732 | 1.09762  |  1.09776 |

这将是当有足够的分时仅创建 1 个蜡烛时的输出。如果足够创建其中两个,则应该有 2 行。

所以,归根结底,我的想法是触发器应不断检查是否有足够的数据来创建蜡烛,如果是,则创建它。

真希望现在的问题是完整的,没有遗漏的信息。 感谢所有评论和建议。

谢谢!

编辑: 由于这是一个实时过程,一秒钟内数据库中可能有 499 个滴答声,下一秒可能有 503 个滴答声。这意味着 1 秒内到达 4 个报价。

作为数据库专家,我的方法是在数据库中使用触发器。

创建第三个 table candle_in_the_making,其中包含尚未聚合到 candles 条目的报价数据。

ticks table 上创建一个 INSERT 触发器(无论 BEFORE 还是 AFTER)执行以下操作:

  • 对于每个插入的报价,添加一行到 candle_in_the_making

  • 如果行数达到 500,计算并插入一个新的 candles 行和 TRUNCATE candle_in_the_making.

如果 ticks 仅在单个线程中插入,这很简单。

如果同时插入ticks,你必须找到一种方法来防止两个线程同时在candle_in_the_making中插入第500个刻度(这样你最终得到501个条目) .我可以想到两种在数据库中执行此操作的方法:

  1. 有一个额外的 table c_i_m_count,它只包含一个数字,即 candle_in_the_making 中的行数。在插入 candle_in_the_making 之前,您 运行 原子

    UPDATE c_i_m_count SET counter = counter + 1 RETURNING counter;
    

    这会锁定该行,因此 counter_in_the_making 中的任何两个 INSERT 都可以有效地序列化。

  2. 使用advisory locks序列化插入线程。特别是,事务级独占锁 将被指示为 pg_advisory_xact_lock 所采取的。