MySQL计算不同开始时间的服务的最低价格

标签 mysql

假设我有一个这样的表:

价格

 -----------------------------------------------------------
| 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_startservice_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。

整体sql script.

关于MySQL计算不同开始时间的服务的最低价格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21581070/

相关文章:

mysql - DECLARE CONTINUE HANDLER FOR NOT FOUND 不工作

mysql - 在 MySQL 数据库中跟踪每个用户的 "blocked users"的最有效方法是什么?

mysql - SQL错误: 1364 Field 'XXXX' doesn't have a default value1

mysql - 更新后重新加载 vagrant

php - xml php mysql utf-8 : Greek chars dont display correct in xml

mysql - Percona 和 MySQL Workbench

sql - mysql 在 NOW() 之前选择两个,在 NOW() 之后选择一个

mysql - 我如何首先对特定国家/地区的 mySQL 数据进行排序,然后是正常顺序?

mysql - 用于数据库设计的抽象/超/子类结构

php - Laravel 多个数据库同时使用