我希望以一种不错的方式跟踪网站上某个商品的价格。一种选择是只有一个像
这样的表create table prices (
name text,
price decimal,
updated timestamp
)
每次更新价格时,只需在此表格中创建一个新行。 但是,我认为这种做法不是很好,而且很好。在我的情况下,原因如下:
由于这些原因,对于特定项目,例如dove bodywash
,我的价格表可能包含200行,看起来像
'dove soap' | 3.00 | <a new timestamp every 5 minutes>
这似乎有点荒谬。
在我看来,一个更好的解决方案是添加一个额外的price_history
表,该表存储一个项目具有特定价格的时间范围。例如,price_history
可能包含列
name | price | created_at | updated_at
并且期望的行为是每当我更新dove soap
的价格时,会有一个触发器会自动检查价格是否已经改变 - 如果它没有改变,那么只需更改price_history中相应条目的updated_at
,如果有,则在price_history中为新价格创建一个新行。作为执行的一个例子,我想:
1)在时间1我做insert into prices ('dove soap', 3.00)
。此时,price_history表将包含一行
|'dove soap' | 3.00 | time1 | null |
2)在时间2我做update prices set price = 3.00 where name = 'dove soap'
。现在price_history表看起来像
'dove soap' | 3.00 | time1 | time2
3)在时间3,价格仍为3.00。 price_history应该看起来像
'dove soap' | 3.00 | time1| time3
4)在时间4,价格是3.50。 price_history现在应该是这样的:
'dove soap' | 3.00 | time1 | time3
'dove soap' | 3.50 | time4 | null
我的问题是
非常感谢上述任何一点的任何建议!
谢谢: - )
编辑:我应该包括我看到的一件事是temporal_tables
postgresql扩展,它使用类似的价格/ price_history /设置。它的问题在于,每次价格更新时,它似乎会在price_history表中创建一个新行,如果它没有改变则会发生事件,这会使目的失效。在我看来,没有办法修改这种默认行为,但如果有人知道更好,请告诉我!
答案 0 :(得分:2)
这是一个可以工作的设计,使用一个表和一个视图...我做了几个假设,即你并不真正关心跟踪上次更新时间(但见下文),并且结束了最新参赛作品的时间是2999-12-31 23:59:59。 (你可以把它留空,但我不喜欢空值,并且在那里有一个日期意味着你可以在查询之间做...)。
创建price_history_table:
create table price_history(
article_id integer, -- I like using article ids
article_name text, -- I don't like using reserved words for columns
price decimal not null,
start_time timestamp not null,
end_time timestamp not null default '2999-12-31 23:59:59')
(如果您不想使用article_id,请在下面将article_id替换为article_name,尽管您可能会考虑将项目描述存储在单独的表中并仅在“大”表中存储id。占用较少的空间磁盘和少写的一列。)
在article_id和结束时间创建一个唯一约束:
alter table price_history add constraint article_id_end_time unique (article_id,end_time)
...以及article_id和start_time
上的主键alter table price_history add constraint pk_price_history primary key (article_id,start_time);
我认为让这些约束阻止你在表中输入垃圾是很重要的,因为重复的时间会破坏你的逻辑。
现在触发功能。如果价格没有改变,触发器什么也不做,否则它会将最后一条记录的end_time更新为新的start_time。
CREATE FUNCTION update_enddate()
RETURNS trigger
LANGUAGE 'plpgsql'
COST 100.0
VOLATILE NOT LEAKPROOF
AS $BODY$
BEGIN
if EXISTS (select * from price_history where article_id = NEW.article_id AND end_time ='2999-12-31 23:59:59'::timestamp AND price = NEW.price) THEN
-- the price hasn't changed, don't do anything
RETURN NULL;
ELSE --Set the end date to the new startdate
update price_history set end_time = NEW.start_time where article_id = new.article_id AND end_time ='2999-12-31 23:59:59'::timestamp;
RETURN NEW;
END IF;
END;
$BODY$;
触发器本身。
CREATE TRIGGER trigger_update_enddate BEFORE INSERT on price_history FOR EACH ROW EXECUTE PROCEDURE update_enddate();
查看最新记录。
CREATE VIEW prices AS
SELECT article_id,article_name,price,start_time from price_history where end_time ='2999-12-31 23:59:59'::timestamp;
如果您想了解某个更新的价格是否已更改,您可以尝试
等内容SELECT * from price_history where start_time <= mytime and end_time > mytime;
请注意,您需要对“之间”查询稍微小心,因为它们包含起点和终点,如果您的时间恰好与start_time匹配,则可能会出现重复。
start_time等于上次更改价格的时间。您可以将更新时间存储在不同的表中,只需加入start_time&lt; = update_time和end_time&gt; update_time为您提供“完整历史记录”。
如果您不断添加记录,则不确定索引的性能,因此如果您没有索引,可能会获得更好的性能。