我正在开展一个项目,我需要在这个项目中计算选定租赁期内的度假屋价格。我需要一些帮助来构建一个SQL查询,该查询结合了以下表格并将数据转换为包含每个房屋所请求期间价格的输出。它应包含住宿费用,额外费用类型以及承租人应为每个 cost_type 支付的金额。
我有一张表 costprofiles ,它可以让房主全年有多种价格:
+----------------+----------+--------------+
| costprofile_id | house_id | profile_name |
+----------------+----------+--------------+
| 1 | 312 | summer |
+----------------+----------+--------------+
| 2 | 312 | winter |
+----------------+----------+--------------+
我有一个名为 costprofile_items 的表,它通过外键 costprofile_id 链接到costprofile。如果所选期间的价格使用此 cost_type ,则此表包含承租人应向所有者支付的所有不同金额。每个额外的金额可以通过四种不同的方式计算:
每个金额对总租金价格的贡献方式存储在 calculation_type 列中。这就是 costprofile_items 表的样子:
+---------------------+----------------+--------+-------------+----------------------+
| costprofile_item_id | costprofile_id | amount | cost_type | calculation_type |
+---------------------+----------------+--------+-------------+----------------------+
| 1 | 1 | 20 | usage_cost | per_night |
+---------------------+----------------+--------+-------------+----------------------+
| 2 | 1 | 8.5 | cleaning | per_stay |
+---------------------+----------------+--------+-------------+----------------------+
| 3 | 1 | 0.82 | tourist_tax | per_person_per_night |
+---------------------+----------------+--------+-------------+----------------------+
我还有价格表格,其中每行代表可在 start_date 和 end_date 之间使用的每晚价格( start_date 的工作日等于到达房子的工作日, end_date 的工作日等于出发的工作日)。该行还包含一列 nights ,用于确定子期间需要多长时间才能使用此价格。这就是表格的样子:
+----------+----------+----------------+------------+------------+-----------+--------+
| price_id | house_id | costprofile_id | start_date | end_date | per_night | nights |
+----------+----------+----------------+------------+------------+-----------+--------+
| 1 | 1 | 1 | 2014-08-04 | 2014-12-01 | 60 | 7 |
+----------+----------+----------------+------------+------------+-----------+--------+
| 2 | 1 | 1 | 2014-08-08 | 2014-12-05 | 70 | 3 |
+----------+----------+----------------+------------+------------+-----------+--------+
| 3 | 1 | 2 | 2014-12-01 | 2015-03-02 | 0 | 1 |
+----------+----------+----------------+------------+------------+-----------+--------+
在表格中您可以看到,对于给定的房子,您可以预订8月8日至11日期间,这将花费3 * 70 = 210欧元的住宿。如果您有4人,额外费用为3 * 20 =电费/燃气使用费为60欧元,清洁费为8.5欧元,旅游税为0.82 * 4 * 3 = 9.84欧元。所以你周末的总费用是€288.34。也应该可以将这个周末与例如表格第一行中描述的每周价格的2倍相结合。在这种情况下,8月8日至25日的价格为288.34 + 2 * 582.96 = 1454.26欧元。请注意,只需要从第一个子句点中选择计算类型 per_stay 和 per_person ,因此最后一个示例中的清洁仅支付一次。
我用于计算价格的最后一张表是 prices_per_group 表。此表通过外键 price_id 连接到价格。在上面的价格表中,您可以在最后一行看到每晚的价格等于0.在这种情况下,所有者已经为他在房子里接受的每个人每晚给出了一个价格。这个时期这个价格很活跃。这就是存储不同价格的方式:
+--------------------+----------+------------+-----------+
| price_per_group_id | price_id | group_size | per_night |
+--------------------+----------+------------+-----------+
| 1 | 3 | 5 | 50 |
+--------------------+----------+------------+-----------+
| 2 | 3 | 4 | 45 |
+--------------------+----------+------------+-----------+
正如你可以看到从12月1日(或之后的任何星期一,但3月2日之前)的一周,如果你是5人,则每晚需要50欧元;如果你是4人,则每晚需要45欧元。
我希望现在很清楚我如何存储和计算所有不同的价格。
我设法让这些计算工作,首先使用以下查询查询每个可用房屋的所有成本类型:
SELECT * FROM (
SELECT prices.house_id,
prices.price_id,
prices.costprofile_id,
prices.nights,
prices.start_date,
prices.end_date,
MIN(
prices.per_night + COALESCE(prices_per_group.per_night, 0)
) AS per_night /* Add the price per night from prices and prices_per_group (if one has a non-zero value the other is always zero) */
FROM prices
LEFT JOIN prices_per_group ON prices.price_id = prices_per_group.price_id
WHERE prices.house_id IN (
/* Query that returns a set with the ids of all available houses here */
)
AND (
prices_per_group.price_id IS NULL OR /* If true, no row in prices_per_group is pointing to the price_id currently being evaluated */
prices_per_group.group_size >= 4 /* If true, the group_size satisfies the requested number of persons */
)
GROUP BY prices.price_id
) AS possible_prices
INNER JOIN costprofile_items ON costprofile_items.costprofile_id = possible_prices.costprofile_id
ORDER BY price_id ASC
之后,我使用PHP循环遍历包含特定房屋价格信息的所有行。我从 start_date 开始,使用它可以找到的第一个可用价格行创建步骤并重复这一步,直到我在 end_date 。我当前的方法的问题是它太慢了。对于1000个房屋,网络服务器需要0.3秒的执行时间。也许在我的PHP代码中可以进行一些优化,但是我希望有人能帮助我将这些全部放在SQL中。这种方式,例如按价格排序更容易实现,只需在快速执行上述查询后查询大量结果,我的执行时间就会跳到0.12秒。
欢迎提供所有帮助和建议
答案 0 :(得分:0)
最后,我决定缓存所有价格,而不是实时计算它们。与查询中即时计算相比,这可以带来更好的性能并允许更复杂的定价。每天晚上都有一个cronjob运行,该表会填满21张桌子(每个可能的租用期限一张桌子)。工期定价表包含到货日期的关键值对以及该工期的相应计算价格。 (可选)您可以添加一个用于组大小的列,从而得出每个持续时间,每个组大小和每个到达日期的价格。它需要相当多的数据库记录,但是如果您创建索引,那将非常快。