【发布时间】:2014-08-04 22:34:44
【问题描述】:
我正在处理一个项目,我需要计算在选定租赁期内可用的度假屋价格。我需要一些帮助来构建一个 SQL 查询,该查询结合了下表并将数据转换为包含每所房屋所请求期间的价格的输出。它应包含住宿费用、额外费用类型以及租户应为每个cost_type支付的金额。
我有一个表格costprofiles,它可以让房主在一年中拥有多个价格:
+----------------+----------+--------------+
| costprofile_id | house_id | profile_name |
+----------------+----------+--------------+
| 1 | 312 | summer |
+----------------+----------+--------------+
| 2 | 312 | winter |
+----------------+----------+--------------+
我有一个名为 costprofile_items 的表,它通过外键 costprofile_id 链接到成本配置文件。如果所选期间的价格使用此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 |
+---------------------+----------------+--------+-------------+----------------------+
我还有一个 prices 表,其中每一行代表每晚的价格,可以在 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 连接到 prices。在上面的 prices 表中,您可以在最后一行看到每晚的价格等于 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 秒。
欢迎所有帮助和建议
【问题讨论】:
-
我认为你想创建一个
SUM()的行? -
不幸的是,它比这更复杂。在结果集中,我得到的行仅包含房屋价格有效的开始日期和结束日期。例如,我可能需要 3 次每周价格的行,而我不使用周末价格的行。