从开始日期到结束日期,每周显示计划活动

时间:2018-12-12 17:30:23

标签: mysql sql database mariadb

过去两天来,我一直在挠头-我需要专业的眼睛!

基本上,我试图在1周内为驾驶员显示计划者事件,直到他们关闭为止。如果司机在2018年12月10日至2018年12月21日期间关闭,我希望司机可以将其延至第二天并显示其姓名,直到截止日期为止。现在,结果仅显示当天的驱动程序,而不是每天重复。

这是一个示例数据集:

CREATE TABLE IF NOT EXISTS planner_events (
  planner_id INT(5) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  event_name VARCHAR(100) NOT NULL,     
  event_start_date DATE,    
  event_end_date DATE,
  user_id INT(5) NOT NULL,  
  user_type VARCHAR(10) NOT NULL,
  date_created DATETIME DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO planner_events (event_name, event_start_date, event_end_date, user_id, user_type)
VALUES ('Annual Holiday', '2018-12-12', '2018-12-16', 101, 'driver'), 
('Alex on leave', '2018-12-12', '2018-12-15', 102, 'driver'), 
('Reminder', '2018-12-13', '2018-12-13', 103, 'driver');

CREATE TABLE IF NOT EXISTS drivers (
  driver_id INT(5) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  driver_name VARCHAR(100) NOT NULL, 
  date_created DATETIME DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO drivers (driver_id, driver_name)
VALUES (101, 'Alex'), (102, 'Tom'),(103, 'Trevor');

我已经创建了一个SQL Fiddle,但是默认情况下,SQL Fiddle没有存储seq_0_to_999999表。我正在使用最新版本的MariaDB。

SQL Fiddle Link

如果已安装MariaDB,则可以在本地计算机上复制以上内容中的表和SQL语句。

基本上,在代码中,使用in_array函数,如果驱动程序在给定日期关闭,我将从可用性框中删除驱动程序。我正在尝试通过1个查询来实现这一点,在该查询中检索一周中的空天或驱动程序已关闭。当前,该查询仅在给定日期存在条目时才起作用,问题是,如果结束日期尚未结束,则该查询不会继续。

enter image description here

这里是执行当前查询的一个很好的例子。如果您查看下面的屏幕,马里奥(Mario)直到2019年1月1日关闭,但第19、20、21、22和23天为空白,不要说出他的名字。他们也许需要在某个地方加入CROSS JOIN-进行逻辑思考!

enter image description here

任何帮助将不胜感激,感谢您超时!

3 个答案:

答案 0 :(得分:2)

我发现您的提琴中的查询有点难以理解。但是我认为您想要的是这样:

select *
from planner_events e
join drivers d on d.driver_id=e.user_id
where e.event_start <= @enddate and e.event_end >= @startdate
  and e.user_type='driver'

@startdate是您感兴趣的时间段的第一天,@ enddate是最后一个日期。如果范围的大小始终相同,一个星期或其他任何时间,则@enddate可以用计算代替。

这应该为您列出所有事件与所需日期范围重叠的驾驶员。如果您想要的是在该日期范围内没有任何活动的所有驾驶员,则只需取消日期测试即可。

哦,当然,您应该列出您实际感兴趣的任何字段,而不是“ select *”。我只是在那儿懒惰。

更新

啊,我明白了。您需要每天都有哪些人可用,而不只是一周中某个时间有谁可用。

据我所知,要做到这一点,您需要一个带有每天记录的表格。创建此类表的方式有很多种,我不知道使用标准SQL的方式。如果创建该表是个问题,我们可以解决这个问题,但是让我假设不是,并且该表存在并且被称为“工作日”,并且每个记录都包含一个日期字段“ date1”。

然后可以这样查询:

select w.date1, d.driver_id, d.driver_name
from workdays w
cross join drivers d
where w.date1 between @start and @end
 and not exists (select * from planner_event 
   where event_start<=w.date1 and event_end>=w.date1 and user_id=d.driver_id and user_type='driver')
order by w.date1, d.driver_id

这将提供一个包含日期和可用驱动程序列表的结果集,然后您必须使用代码将其格式化为所需的表。如果您要查找的结果集是每天有一列,每个驱动程序有一行,等等,那么我敢肯定,我们可以做到这一点,必须多花一点时间。我认为这将是一个混乱的查询,每天都有一个子查询。

更新2

啊。如果我们知道该期间是一周,那么就不需要工作日表。我们可以这样做:

select d.driver_id, d.driver_name,
  case when exists (select * from planner_events where '2018-12-31' between event_start_date and event_end_date and user_id=d.driver_id) then 'N' else 'Y' end as Monday,
  case when exists (select * from planner_events where DATE_ADD('2018-12-31', INTERVAL 1 DAY) between event_start_date and event_end_date and user_id=d.driver_id) then 'N' else 'Y' end as Tuesday,
  case when exists (select * from planner_events where DATE_ADD('2018-12-31', INTERVAL 2 DAY) between event_start_date and event_end_date and user_id=d.driver_id) then 'N' else 'Y' end as Wednesday,
  case when exists (select * from planner_events where DATE_ADD('2018-12-31', INTERVAL 3 DAY) between event_start_date and event_end_date and user_id=d.driver_id) then 'N' else 'Y' end as Thursday,
  case when exists (select * from planner_events where DATE_ADD('2018-12-31', INTERVAL 4 DAY) between event_start_date and event_end_date and user_id=d.driver_id) then 'N' else 'Y' end as Friday
from drivers d
order by d.driver_id

答案 1 :(得分:1)

有一个叫Andriy(https://dba.stackexchange.com/users/6965/andriy-m)的绅士,他过去曾帮助过我,他已经回答了我的期望。也感谢@Jay发布了该问题的另一个答案。

这是正确的SQL查询:

SELECT sub.planner_start_date, COALESCE(d.driver_name, 'N/A') AS driver_name, e.planner_id, e.event_name, e.event_start_date, e.event_start_time, e.event_end_date, e.event_end_time
FROM
( SELECT
        '2018-12-30' + INTERVAL seq.seq DAY AS planner_start_date
     FROM
        seq_0_to_999999 AS seq
     WHERE
        seq.seq <= TIMESTAMPDIFF(DAY, '2018-12-30', '2019-01-05')
    ) as sub
LEFT JOIN planner_events AS e ON e.event_start_date <= sub.planner_start_date AND e.event_end_date >= sub.planner_start_date
LEFT JOIN drivers AS d ON e.user_id = d.driver_id AND e.user_type = 'driver'

感谢大家在此方面的所有帮助。

答案 2 :(得分:0)

在我看来,这就是您需要的所有查询:

SELECT d.driver_id
     , d.driver_name
     , e.planner_id
     , e.event_name
     , e.event_start_date
     , e.event_end_date
  FROM drivers d 
  JOIN planner_events e 
    ON e.user_id = d.driver_id;

所有其他内容似乎都是显示问题-最好在应用程序代码中解决。