我创建了一个存储过程:

CREATE PROCEDURE `CheckSlotAvailability`(IN slotId INT)
BEGIN
    DROP TEMPORARY TABLE IF EXISTS tempres1;
    CREATE TEMPORARY TABLE tempres1
    SELECT
        `slot_id`,
        `customer_id`,
        IFNULL(`start`, 'empty') AS `start`,
        IFNULL(`end`, 'empty') AS `end`,
        IFNULL(`in`, 'empty') AS `in`,
        IFNULL(`out`, 'empty') AS `out`,
        `parking_type`,
        `status`
    FROM reservations;

    DROP TEMPORARY TABLE IF EXISTS tempres2;
    CREATE TEMPORARY TABLE tempres2
    SELECT
        slot_id,
        `customer_id`,
        MIN(`start`) AS `start`,
        MAX(`end`) AS `end`,
        MIN(`in`) AS `in`,
        MAX(`out`) AS `out`,
        `parking_type`,
        `status`
    FROM tempres1
    GROUP BY slot_id, customer_id;

    DROP TEMPORARY TABLE IF EXISTS tempres3;
    CREATE TEMPORARY TABLE tempres3
    SELECT * FROM tempres2 WHERE slot_id = slotId;

    SELECT * FROM TEMPRES3;
END

它返回停车位的保留小时数:

enter image description here

从该表中:

enter image description here

我们如何从这件事中获得可用的工作时间?

比方说,我 for each Slot_id设置了小时范围,

起点:2023-05-30 15:00:00 完:9999-12-30 00:00:00

由于基于2023-05-30 18:00:00以上的镜像,直到2023-05-30 20:00:00被占用,这意味着唯一可用的小时数如下:

  1. 2023-05-30 15:00:002023-05-30 17:59:59
  2. 2023-05-30 20:00:009999-12-30 00:00:00

请注意,一个时段可能会有多个预订,我只需要得到可用的时间.

加入时间:清华2007年01月25日下午3:33

几天来我一直在努力解决它,但对我来说似乎是不可能的:

先谢谢你.

推荐答案

如果你知道一些概念,逻辑就不那么复杂了.假设你有这occupied个约会对象:

start_dt end_dt
... ...
2023-06-01 06:00:00 2023-06-01 18:00:00
2023-06-02 06:00:00 2023-06-02 18:00:00
2023-06-03 06:00:00 2023-06-03 18:00:00
2023-06-04 06:00:00 2023-06-04 18:00:00
... ...

和此输入范围:

@dt1 @dt2
2023-06-01 12:00:00 2023-06-04 12:00:00

然后,首先找出与该范围相交的所有入住率.结果将是这4行:范围从第1行的中间开始,在第4行的中间结束.

现在将结果中的开始日期和结束日期放到一列中:结束日期应该被视为available槽的开始日期,反之亦然.将输入的开始日期和结束日期添加到此列中以确保完整.

最后,使用lag函数将结束日期与开始日期匹配.

类似于:

set @dt1 = '2023-06-01 12:00:00';
set @dt2 = '2023-06-04 12:00:00';
with cte1(dt, type) as (
    select start_dt, 'e' from t where @dt2 > start_dt and end_dt > @dt1
    union all
    select end_dt, 's' from t where @dt2 > start_dt and end_dt > @dt1
    union all
    select @dt1, 's'
    union all
    select @dt2, 'e'
), cte2(dt1, dt2) as (
    select dt, case when type = 's' and lead(type) over (order by dt) = 'e' then lead(dt) over (order by dt) end
    from cte1
)
select *
from cte2
where dt2 is not null
order by dt1

DB<>Fiddle

Mysql相关问答推荐

括号在SQL查询中的作用?

客户跨订阅的跨时间线计数

JPA对具有动态键和动态值的JSON列的原生查询

使用字符串文字与使用日期文字时的SQL行为

mysql 获取每个单词的第一个字母

Next-key lock explication - 范围的主键

仅当其他行相等时才 Select 行值

了解 Spring 和数据库级别的事务?

为什么这个 NOT NULL 到 NULL 迁移会触发大量 I/O 操作?

如何在每个国家/地区查询 GHTorrent(类 SQL 语言)的最常用语言

我在查询中没有得到正确的结果

在 spring-boot jpa hibernate 中 >4<24 后与 Db 的连接终止

按日期和时间降序排序?

仅在 MYSQL DATEDIFF 中显示小时数

MySQL行格式:固定和动态之间的区别?

Sequelize Query 查找日期范围内的所有记录

MySQL术语约束与外键的区别?

更改 Laravel 的 created_at 和 updated_at 的名称

"SELECT COUNT(*)" 很慢,即使有 where 子句

MySQL中的base64编码