基于其他 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 行。
所以,归根结底,我的想法是触发器应不断检查是否有足够的数据来创建蜡烛,如果是,则创建它。
- 这是个好主意还是我应该坚持 python 脚本?
- 我的方法可以实现吗?
- 我做错了什么?
- 我该怎么办以及我应该如何处理这种情况?
真希望现在的问题是完整的,没有遗漏的信息。
感谢所有评论和建议。
谢谢!
编辑: 由于这是一个实时过程,一秒钟内数据库中可能有 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个条目) .我可以想到两种在数据库中执行此操作的方法:
有一个额外的 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
都可以有效地序列化。
使用advisory locks序列化插入线程。特别是,事务级独占锁 将被指示为 pg_advisory_xact_lock
所采取的。
好吧,既然我的最后两个问题(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 行。
所以,归根结底,我的想法是触发器应不断检查是否有足够的数据来创建蜡烛,如果是,则创建它。
- 这是个好主意还是我应该坚持 python 脚本?
- 我的方法可以实现吗?
- 我做错了什么?
- 我该怎么办以及我应该如何处理这种情况?
真希望现在的问题是完整的,没有遗漏的信息。 感谢所有评论和建议。
谢谢!
编辑: 由于这是一个实时过程,一秒钟内数据库中可能有 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个条目) .我可以想到两种在数据库中执行此操作的方法:
有一个额外的 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
都可以有效地序列化。使用advisory locks序列化插入线程。特别是,事务级独占锁 将被指示为
pg_advisory_xact_lock
所采取的。