假设我有一个这样的表:
价格
-----------------------------------------------------------
| service_id | starting_time | ending_time | price_per_hour |
-----------------------------------------------------------
| 1 | 08:00:00 | 10:00:00 | 90 |
-----------------------------------------------------------
| 1 | 10:00:00 | 11:00:00 | 50 |
-----------------------------------------------------------
| 1 | 11:00:00 | 15:00:00 | 80 |
-----------------------------------------------------------
现在我的网页的用户想要找到价格最低的服务提供商。他们告诉我服务的开始时间、持续时间和(这是棘手的部分)开始时间的容忍度。比如说,服务应该在上午 10 点开始,应该持续 2 小时,但他们愿意提前或晚一小时来(距离开始时间+/- 1 小时)。
我似乎无法想出一个查询的想法来为我提供尽可能最低的价格,具体取决于服务是在上午 9 点、上午 10 点还是上午 11 点开始。启动时间容差可能会有所不同。这很简单,如果没有容差,您只需从适用于服务时间的价格中选择所有行,计算它们在价格中的份额,然后对子查询求和。但是我如何将可变的开始时间因素引入其中呢?
这是一个简化的查询,用于在知道服务的确切起点的情况下计算价格。 :service_start
和 service_end
是占位符。
SELECT SUM(t1.price) FROM
(SELECT price_per_hour * TIME_TO_SEC( TIMEDIFF( IF(ending_time < :service_end,
ending_time, :service_end), IF(starting_time < :service_start, :service_start,
starting_time) ) ) / 3600 AS price FROM prices WHERE service_id = 1 AND NOT
(starting_time >= :service_end OR ending_time <= :service_start)) AS t1
现在我不知道接下来该往哪里走。如何引入服务开始时间的可变性。
编辑:
好吧,我想我以前懒得深入思考这个问题。我相信使用 MySQL 无法完成此操作。我已经将其分解为可以解决该问题的数学方程,并且我相信这不是您可以在 MySQL 中实现的东西(两个带有许多变量的方程)。我认为 PHP 端必须进行一些强力计算才能得到我想要的东西。
在这种情况下,我希望最小化 x * 90 + y * 50 + z * 80,其中 x、y、z 是在给定某些条件(例如 x、y、z%)的情况下从每个价格范围获取的小时数0,5 = 0(半小时步长),x+y+z = 2,等等
编辑2:
我会更详细地描述这个问题,因为我似乎不够具体:
我有与此问题相关的三个表格:
服务
-----------------------------------------------------------------------------------------------
| service_id | service_type_id | provider_id | name | starting_time | ending_time |
-----------------------------------------------------------------------------------------------
| 2 | 1 | 3 | 2014-02-07 08:00:00 | 2014-02-07 23:00:00 |
-----------------------------------------------------------------------------------------------
价格(更多价目表)
------------------------------------------------------------------------------
| service_type_id | provider_id | starting_time | ending_time | price_per_hour |
------------------------------------------------------------------------------
| 1 | 3 | 08:00:00 | 10:00:00 | 90 |
------------------------------------------------------------------------------
| 1 | 3 | 10:00:00 | 11:00:00 | 50 |
------------------------------------------------------------------------------
| 1 | 3 | 11:00:00 | 15:00:00 | 80 |
------------------------------------------------------------------------------
| 1 | 3 | 15:00:00 | 23:00:00 | 70 |
------------------------------------------------------------------------------
service_slots
-----------------------------------------------------------------------------------
| service_slot_id | service_id | starting_time | ending_time | booked |
-----------------------------------------------------------------------------------
| 1 | 2 | 2014-02-07 08:00:00 | 2014-02-07 09:00:00 | 1 |
| 2 | 2 | 2014-02-07 09:00:00 | 2014-02-07 17:00:00 | 0 |
| 3 | 2 | 2014-02-07 17:00:00 | 2014-02-07 19:00:00 | 1 |
| 4 | 2 | 2014-02-07 19:00:00 | 2014-02-07 21:00:00 | 1 |
| 5 | 2 | 2014-02-07 21:00:00 | 2014-02-07 23:00:00 | 0 |
-----------------------------------------------------------------------------------
第一个表包含提供商的服务时间表。该提供商表示,他们将在上午 8 点至晚上 11 点之间提供该服务。您可以根据需要预订任意多的休息时间(例如网球场预订)。
他们还有这些服务的定价。此定价表示每天(在价目表有效期内),该服务在该时间和该时间之间的费用是这样或那样的。您可以预订跨价格范围的服务。也就是说,如果价目表显示上午 8 点至 10 点之间的服务费用为 90 美元,上午 10 点至 11 点之间的服务费用为 50 美元,那么您在 9 点至 11 点之间预订就完全没问题。那么您的预订将适用两个价格范围。
第三个表保存有关特定服务的哪个 block (槽)已被预订的信息。
我所做的是首先查询 service_slots 以获得可用 block ,然后我需要获取该 block 的整个持续时间的价格,因为知道价格可能会在该 block 的持续时间中间发生变化。
我希望这次我能让自己更清楚:)
最佳答案
经过大量编辑,旧帖子不见了!
首先,检查我的代码。
我的测试表:
CREATE TABLE IF NOT EXISTS price(
id INT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
pid INT(20) NOT NULL,
staring_time DATETIME,
ending_time DATETIME,
price INT(20) NOT NULL
);
以及查询:
SET @start_pref = '2014-02-07 02:00:00';
SET @end_pref = '2014-02-07 04:00:00';
SELECT
*,
(
SELECT id
FROM price
WHERE
pid = p.pid AND
starting_time <= @start_pref AND
ending_time > @start_pref
) AS id_first,
(
SELECT id
FROM price
WHERE
pid = p.pid AND
ending_time >= @end_pref AND
starting_time < @end_pref
) AS id_last,
(
SELECT IF(
id_first = id_last,
(
SELECT HOUR(TIMEDIFF(@end_pref, @start_pref)*price)
FROM price
WHERE id = id_first AND pid = p.pid
),
(
(
SELECT HOUR(TIMEDIFF(ending_time, @start_pref)*price)
FROM price
WHERE id = id_first AND pid = p.pid
) + (
SELECT HOUR(TIMEDIFF(@end_pref, starting_time)*price)
FROM price
WHERE id = id_last AND pid = p.pid
)
)
) FROM price WHERE pid = p.pid AND id = id_first
) AS total
FROM price p
WHERE
starting_time <= @start_pref AND @start_pref < ending_time
ORDER BY total ASC;
这只适用于 @start_pref 和 @end_pref 覆盖 1 - 2 个连续的时间计划。
但是,当首选时间覆盖超过 2 条记录时,它不起作用。
示例:
Starting pref time: 1am
Ending pref time: 5am
For one specific provider
1am - 2am - $10
2am - 3am - $20
4am - 5am - $30
这是因为我在开始和完成查询时没有事先想到这一点。
现在,如果有两个或更多,您需要更多子查询来查找这些 ID,然后将它们添加到我的 SELECT IF(
子查询中。
另外,请注意我是如何添加/添加列 id
的?这样我就可以轻松判断该 id
是否属于当前查询中的同一个 pid
。
PID 是提供商 ID。
关于MySQL计算不同开始时间的服务的最低价格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21581070/