如何查找具有多个类型资产的asset_type的下一个可用时间段

时间:2017-01-16 16:12:29

标签: php mysql sql

我有一张预订我资产的桌子。 我们有n个资产$nof,可以在开放时间$open和结束时间$closed

之间以15分钟为增量进行保留

如果所选时间点没有任何可用资产,我想找到下一个可用时间,其中至少有一项资产可用60分钟。

我现在在表格上以15分钟的增量进行迭代以检查可用性,并在availability > 0发生超过4次(4 * 15m)时将其重置为availability ==0时重新启动循环。

但这感觉不对。而且它很慢:(

这是我从数据库中提取的一个例子。 asset_type来自另一个表,该表链接在asset_id表中的asset上。为清楚起见,我省略了这个连接,并将其表示为列。

Reservations
id   | asset_id | asset_type | start            | end              |
-----+----------+------------+------------------+------------------+ 
2    | 67       | 99         | 2017-01-16 11:00 | 2017-01-16 14:00 |
4    | 67       | 99         | 2017-01-16 14:30 | 2017-01-16 15:45 |
3    | 54       | 99         | 2017-01-16 12:30 | 2017-01-16 16:00 |

总共有2种99型资产可供选择:67和54.

所以:

// nextAvailable($assesTime, $gap_in_minutes, $nof_assets, $asset_type);

echo nextAvailable('2017-01-16 11:30', 60, 2, 99);
// 15:45, 
// not 14:00 as there is only 30 minutes between res#2 and #4

解决这个问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

好的,让我们做一些数据!

DECLARE @DateToCheck DATETIME = '2017-01-16 11:30'
DECLARE @LengthOfTimeInMinutes INT = 60
DECLARE @TimeSlotLengthInMinutes INT = 15

DECLARE @Reservations TABLE
(
    id INT,
    asset_id INT,
    asset_type INT,
    startdt DATETIME,
    enddt DATETIME
)

INSERT INTO @Reservations
( id, asset_id, asset_type, startdt, enddt )
VALUES
( 2, 67, 99, '2017-01-16 11:00', '2017-01-16 14:00' ),
( 4, 67, 99, '2017-01-16 14:30', '2017-01-16 15:45' ),
( 3, 54, 99, '2017-01-16 12:30', '2017-01-16 16:00' );

现在我要创建一个数字表来生成大约15分钟的时隙,这样我们就可以看到已填充的插槽和仍然可用的插槽

DECLARE @number_of_numbers INT = 672; --Total Number of TimeSlots to Generate at 15 Minutes, 4 per Hour, 96 per day, 672 per week

;WITH 
a AS (SELECT 1 AS i UNION ALL SELECT 1),
b AS (SELECT 1 AS i FROM a AS x, a AS y),
c AS (SELECT 1 AS i FROM b AS x, b AS y),
d AS (SELECT 1 AS i FROM c AS x, c AS y),
e AS (SELECT 1 AS i FROM d AS x, d AS y),
f AS (SELECT 1 AS i FROM e AS x, e AS y),
numbers AS 
(
    SELECT TOP(@number_of_numbers)
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS number
    FROM f
), Rooms AS
(
    SELECT DISTINCT r.asset_id FROM @Reservations r
), TimeSlots AS
(
    SELECT DATEADD(MINUTE, (n.number - 1) * @TimeSlotLengthInMinutes, DATEADD(DAY, DATEDIFF(DAY, 0, @DateToCheck), 0)) AS TimeSlot
    FROM numbers n
), RoomSlots AS
(
    SELECT r.asset_id, t.TimeSlot
    FROM TimeSlots t
    CROSS JOIN Rooms r
), Reserved AS
(
    SELECT rs.asset_id, rs.TimeSlot, r.id, r.startdt, r.enddt
    FROM RoomSlots rs
    LEFT JOIN @Reservations r
        ON r.asset_id = rs.asset_id
        AND rs.TimeSlot >= r.startdt AND rs.TimeSlot < r.enddt
), LookingForSlots AS
(
    SELECT st.asset_id, st.TimeSlot AS StartSlot, DATEADD(MINUTE, @LengthOfTimeInMinutes, st.TimeSlot) AS EndSlot
    FROM RoomSlots st
)

现在在上面的代码中,我为我正在检查的那一周的每个可用资产制作了一系列15分钟的时间段 - (roomslots) 然后我加入了roomlots到保留的资产,以全面了解每个房间的使用/可用时段。

现在让我们来寻找一些开放点:

    SELECT top 10 l.asset_id, l.StartSlot, l.EndSlot, r.*
    FROM LookingForSlots l
    LEFT JOIN Reserved r
        ON l.asset_id = r.asset_id
        AND l.StartSlot < r.enddt
        AND l.EndSlot > r.startdt
    WHERE r.id IS NULL
        AND l.StartSlot >= @DateToCheck
    ORDER BY l.StartSlot, l.asset_id

这是输出:

asset_id    StartSlot   EndSlot asset_id    TimeSlot    id  startdt enddt
54  2017-01-16 11:30:00.000 2017-01-16 12:30:00.000 NULL    NULL    NULL    NULL    NULL
67  2017-01-16 15:45:00.000 2017-01-16 16:45:00.000 NULL    NULL    NULL    NULL    NULL
54  2017-01-16 16:00:00.000 2017-01-16 17:00:00.000 NULL    NULL    NULL    NULL    NULL
67  2017-01-16 16:00:00.000 2017-01-16 17:00:00.000 NULL    NULL    NULL    NULL    NULL
54  2017-01-16 16:15:00.000 2017-01-16 17:15:00.000 NULL    NULL    NULL    NULL    NULL
67  2017-01-16 16:15:00.000 2017-01-16 17:15:00.000 NULL    NULL    NULL    NULL    NULL
54  2017-01-16 16:30:00.000 2017-01-16 17:30:00.000 NULL    NULL    NULL    NULL    NULL
67  2017-01-16 16:30:00.000 2017-01-16 17:30:00.000 NULL    NULL    NULL    NULL    NULL
54  2017-01-16 16:45:00.000 2017-01-16 17:45:00.000 NULL    NULL    NULL    NULL    NULL
67  2017-01-16 16:45:00.000 2017-01-16 17:45:00.000 NULL    NULL    NULL    NULL    NULL

现在你可以看到第一个找到的插槽是11:30的asset_id 54,下一个可用于15:45的asset_id 67.

它以基于集合的方式运行得相当快,你可以根据生成的房间数/时间段来调整速度(我只生成了一周的数据,你可以将它设置得更低,只是生成一天来反对如果你有更多的房间。

Eek,对不起,我没有在那里意识到MySQL,你可以将其中的大部分转化为表来进行相同的计算(或者如果你有sql server或postgres,他们理解ctes)