属于(日期)范围类型及其交集的权重总和

问题描述 投票:0回答:1

我正在使用 PostgreSQL 16 为我们的前台/接待处创建一个酒店预订工具。为了回答预订请求,我需要总价和相关的每日住宿价格。

当前设置+虚拟数据:dbfiddle.uk

表格简短概述:

category_prices

该表存储每个房间类别的
base_prices
。在任何时候,每个类别都只有一个“活动”数据集。 => 没有重叠,每个日期和类别只有一个价格。

price_adjustments

该表包括意外的价格上涨,主要是由于入住率增加。在此表中(理论上)间隔/日期范围之间可以有任意数量的重叠。属于这些区间的价值/价格必须相应地相加。

我当前的尝试计算每次住宿/间隔的总

base_price
和总
price_adjustment
并将它们相加,但我不知道如何计算每日价格(甚至从哪里开始):

SELECT
    hb.booking_id,
    hb.guest_name,
    hb.room_category_id,
    hb.booking_period,
    SUM((
        upper(hb.booking_period * cp.valid_period) -
        lower(hb.booking_period * cp.valid_period)
    ) * cp.base_price) + subquery.booking_price_adjustment AS total_price
FROM
    hotel_bookings hb
JOIN category_prices cp ON hb.room_category_id = cp.room_category_id
    AND hb.booking_period && cp.valid_period
LEFT JOIN (
    SELECT
        hb.booking_id,
        COALESCE(SUM((
            upper(hb.booking_period * pa.valid_period) -
            lower(hb.booking_period * pa.valid_period)
        ) * pa.price_adjustment), 0) AS booking_price_adjustment
    FROM
        hotel_bookings hb
    LEFT JOIN price_adjustments pa ON hb.room_category_id = pa.room_category_id
        AND hb.booking_period && pa.valid_period
    GROUP BY
        hb.booking_id
) subquery ON hb.booking_id = subquery.booking_id
GROUP BY
    hb.booking_id,
    hb.guest_name,
    hb.room_category_id,
    hb.booking_period,
    subquery.booking_price_adjustment;

我对数据库相当陌生(这是我的第一个子查询)。

我试图找出一种方法来生成包含/返回类似内容的对象/数据集/数组/SELECT:

{ interval_1 : relevant_base_price + sum(relevant_price_adjustments)
, interval_2 : relevant_base_price + sum(relevant_price_adjustments)
, ...
, interval_n : relevant_base_price + sum(relevant_price_adjustments)}

其中间隔没有重叠,并且它们的并集等于初始间隔/日期范围,但我每次尝试都失败了。

sql postgresql date-range
1个回答
1
投票

您询问每日价格

SELECT bp.booking_id, bp.guest_name, bp.room_category_id
     , d.the_day::date
     , bp.base_price
     , COALESCE(pa.sum_price_adjustment, 0) AS sum_price_adjustment
     , COALESCE(sum(bp.base_price)           OVER (PARTITION BY bp.booking_id), 0)
     + COALESCE(sum(pa.sum_price_adjustment) OVER (PARTITION BY bp.booking_id), 0) AS total_price_of_booking
FROM  (
   -- days not covered in category_prices are lost!
   SELECT hb.booking_id
        , hb.guest_name, hb.room_category_id
        , hb.booking_period * cp.valid_period AS bp_period
        , cp.base_price
   FROM   hotel_bookings  hb
   JOIN   category_prices cp ON hb.room_category_id = cp.room_category_id 
                            AND hb.booking_period && cp.valid_period
   ) bp
CROSS  JOIN generate_series(lower(bp.bp_period)::timestamp
                          , (upper(bp.bp_period) - 1)::timestamp
                          , interval '1 day') AS d(the_day)
CROSS  JOIN LATERAL (  -- can be INNER JOIN because agg always produces row
   SELECT sum(price_adjustment) AS sum_price_adjustment
   FROM   price_adjustments pa
   WHERE  pa.room_category_id = bp.room_category_id
   AND    pa.valid_period @> d.the_day::date
   ) pa
ORDER  BY bp.booking_id, d.the_day;

小提琴

每次预订每天一行,包含底价和价格调整总和。
加上预订的总价(可选)。

注释

日期范围存储时包含包含下限和排除上限。参见:

如果

category_prices
中的条目不完整或重叠,我的查询会产生不正确/缺失的结果。确保基础数据一致。

此外,请务必拥有适用的索引以加快速度。

© www.soinside.com 2019 - 2024. All rights reserved.