酒店预订系统的按日期价格数据库设计(存储每个日期与在运行时计算)
Price per date database design for hotel reservation system (store each date vs calcul it at runtime)
我有一个类似于 this question 的要求,我需要存储每个日期的价格(价格随季节变化),我设计了波纹管模型:
room_calendar :
room_id :
date :
price:
我必须存储大约一年的日期,然后 运行 一个查询以获取 x 个日期范围的所有价格和 sum() 所有价格。
我觉得这个方法不错,缺点是数据库中的数据量大,数据库记录多的时候查询性能不佳。
我想到了另一种方法:
(calcul date at runtime) Yes I know! it may sound crazy
db model:
room_calendar :
room_id :
date_rule: <- store a dateutil rrule
price:
results:
{'room_id': {'dates': <dateutil.rrule.rrule object at 0x7fa2a8e3bda0>, 'price': 100}}
{'room_id': {'dates': <dateutil.rrule.rrule object at 0x7fa2a8e3bda0>, 'price': 150}}
然后:
dates_to_reserve = [datetime(2020, 1, 1), datetime(2020, 1, 2), datetime(2020, 1, 3)]
room_price.objects.filter(date_rule__in=dates_to_reserve)
当然,我必须创建一个支持商店 dateutil.rrule
的自定义字段,当我使用 __in
查询它时,请点击 dateutil.rrule
[= 的 __contains__
方法21=]
抱歉我无法用更好的方式表达一切,抱歉我的英语不好
你有比第一种方法更好的方法吗?
参与第二种方法有什么意义吗?
你会怎么做?存储每个日期或在 运行time
计算它
编辑
感谢您的评论@iain-shelvington:
影响价格的规则有多复杂?每个房间的规则是否不同?
- 每个房间的规则都不一样
- 一个房间有多个规则
- 每个规则可能是每月或每周,主要是
你能举个房间的例子吗?它的基本价格和每个日期的最终价格?
Ej.:
Room standard > price: 150 > date_rule: from Jan 2020 weekly on weekdays until Feb 25 2020
Room standard > price: 170 > date_rule: from Jan 2020 weekly on weekends until Feb 25 2020
Room standard > price: 180 > date_rule: from Feb 2020 weekly on weekends until May 26 2020
我开发了一个基于 dateutil.rrule 的应用程序,可以正确处理更复杂的规则,所以规则不会有问题。
编写一个在 运行 时间按日期计算价格的高效算法将是问题所在
谢谢
我将 dateutil.rrrule
用于任务管理器应用程序。我将它存储在一个 varchar 字段中,然后在数据库中使用 plpythonu3 编写的函数可以根据需要扩展该值。这是一种方式。
此类函数的一个示例是:
CREATE OR REPLACE FUNCTION public.task_occurrences(t_rrule character varying, start_dt timestamp with time zone, end_dt timestamp with time zone)
RETURNS timestamp with time zone
LANGUAGE plpython3u
SECURITY DEFINER
AS $function$
from datetime import datetime
from dateutil.parser import parse
from dateutil.rrule import rrulestr
rule = rrulestr(t_rrule, ignoretz=True)
next_occ = rule.between(parse(start_dt, ignoretz=True),
parse(end_dt, ignoretz=True), inc=True, count=1)
if next_occ:
return next_occ[0]
else:
return None
$function$
;
这会找到某个日期范围内任务的第一次出现,如果没有,则 returns None/NULL。
另一种选择是将季节性价格存储在单独的 table 中,其中包含季节的开始和结束日期以及相关价格。您可以使用 Postgres 日期范围数学 range types, range operators 将 table 加入房间日期以获取适当的价格。
示例:
CREATE TABLE seasonal_price(id serial, start_date date, end_date date, price numeric);
SELECT price FROM seasonal_price, room_calendar WHERE room_calendar.date <@ daterange(start_date, end_date, '[]');
价格计算规则往往会发生变化,因此我会避免在数据库中对其进行硬编码。
与其存储每一天的价格,不如使用 daterange
类型来保存整个日期范围内的价格。
我有一个类似于 this question 的要求,我需要存储每个日期的价格(价格随季节变化),我设计了波纹管模型:
room_calendar :
room_id :
date :
price:
我必须存储大约一年的日期,然后 运行 一个查询以获取 x 个日期范围的所有价格和 sum() 所有价格。
我觉得这个方法不错,缺点是数据库中的数据量大,数据库记录多的时候查询性能不佳。
我想到了另一种方法:
(calcul date at runtime) Yes I know! it may sound crazy
db model:
room_calendar :
room_id :
date_rule: <- store a dateutil rrule
price:
results:
{'room_id': {'dates': <dateutil.rrule.rrule object at 0x7fa2a8e3bda0>, 'price': 100}}
{'room_id': {'dates': <dateutil.rrule.rrule object at 0x7fa2a8e3bda0>, 'price': 150}}
然后:
dates_to_reserve = [datetime(2020, 1, 1), datetime(2020, 1, 2), datetime(2020, 1, 3)]
room_price.objects.filter(date_rule__in=dates_to_reserve)
当然,我必须创建一个支持商店 dateutil.rrule
的自定义字段,当我使用 __in
查询它时,请点击 dateutil.rrule
[= 的 __contains__
方法21=]
抱歉我无法用更好的方式表达一切,抱歉我的英语不好
你有比第一种方法更好的方法吗?
参与第二种方法有什么意义吗?
你会怎么做?存储每个日期或在 运行time
计算它编辑
感谢您的评论@iain-shelvington:
影响价格的规则有多复杂?每个房间的规则是否不同?
- 每个房间的规则都不一样
- 一个房间有多个规则
- 每个规则可能是每月或每周,主要是
你能举个房间的例子吗?它的基本价格和每个日期的最终价格? Ej.:
Room standard > price: 150 > date_rule: from Jan 2020 weekly on weekdays until Feb 25 2020
Room standard > price: 170 > date_rule: from Jan 2020 weekly on weekends until Feb 25 2020
Room standard > price: 180 > date_rule: from Feb 2020 weekly on weekends until May 26 2020
我开发了一个基于 dateutil.rrule 的应用程序,可以正确处理更复杂的规则,所以规则不会有问题。 编写一个在 运行 时间按日期计算价格的高效算法将是问题所在
谢谢
我将 dateutil.rrrule
用于任务管理器应用程序。我将它存储在一个 varchar 字段中,然后在数据库中使用 plpythonu3 编写的函数可以根据需要扩展该值。这是一种方式。
此类函数的一个示例是:
CREATE OR REPLACE FUNCTION public.task_occurrences(t_rrule character varying, start_dt timestamp with time zone, end_dt timestamp with time zone)
RETURNS timestamp with time zone
LANGUAGE plpython3u
SECURITY DEFINER
AS $function$
from datetime import datetime
from dateutil.parser import parse
from dateutil.rrule import rrulestr
rule = rrulestr(t_rrule, ignoretz=True)
next_occ = rule.between(parse(start_dt, ignoretz=True),
parse(end_dt, ignoretz=True), inc=True, count=1)
if next_occ:
return next_occ[0]
else:
return None
$function$
;
这会找到某个日期范围内任务的第一次出现,如果没有,则 returns None/NULL。
另一种选择是将季节性价格存储在单独的 table 中,其中包含季节的开始和结束日期以及相关价格。您可以使用 Postgres 日期范围数学 range types, range operators 将 table 加入房间日期以获取适当的价格。
示例:
CREATE TABLE seasonal_price(id serial, start_date date, end_date date, price numeric);
SELECT price FROM seasonal_price, room_calendar WHERE room_calendar.date <@ daterange(start_date, end_date, '[]');
价格计算规则往往会发生变化,因此我会避免在数据库中对其进行硬编码。
与其存储每一天的价格,不如使用 daterange
类型来保存整个日期范围内的价格。