Итак, где я работаю, мои работники работают поочередно по субботам: некоторым сотрудникам назначают работать 1-й и 3-й субботы каждого месяца, некоторые из них назначаются на работу 2-го и 4-го суббот каждого месяца.
Возникает одна небольшая проблема: есть четыре месяца в году, которые имеют пять суббот. Который достаточно прост в работе: 1-й /3-й сотрудники работают в 1-й и 3-й по субботам в течение года и так далее.
У некоторых лет пять месяцев с пятыми субботами, но мы не говорим об этом прямо сейчас.
В любом случае, чтобы генерировать расписания для моих сотрудников, я сначала использую следующий код для создания списка дат:
select
curdate() - interval (a.a + (10 * b.a) + (100 * c.a)) day as Date
from (
select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) as a
Затем я выбираю даты из подзапроса и присоединяю их к таблице Scheduling, чтобы создать список того, что каждый сотрудник работает с каждой датой.
Все это прекрасно работает, пока пятая суббота не выйдет за их уродливые головы. На данный момент я использую следующий код, чтобы математически определить, в какую пятую субботу года он:
mod(((datediff(date_add(a.date, interval (7-dayofweek(a.date)) day),date_add(subdate(a.Date,dayofyear(a.date-1)), interval (1-dayofweek(subdate(a.Date,dayofyear(a.date-1)))) day))+1)/7),4)
Или, резюмируя, я нахожу количество дней, прошедших с текущего первого воскресенья года до текущей субботы на этой неделе, разделите его на семь, чтобы выяснить, сколько суббот прошло с тех пор, а затем найти по модулю из 4, чтобы выяснить, сколько "лишних" пятых суббот прошло с тех пор.
... и этот код будет отлично работать, если Пятая Суббота не выпадет на неделю, что кратно четырем. К счастью, этого не происходит в этом году, но в следующем году мне нужно выяснить, как с этим бороться.
Есть ли лучший способ математически выяснить, какая пятая суббота месяца в данную пятую субботу?
О чувак. Я как-то переусердствовал над этим SQL. Это было довольно легко. Создайте три временных таблицы: один для хранения завершенной таблицы дат, один для хранения всех дат интереса в вашем периоде и третий стол, чтобы найти пятые субботы:
drop temporary table if exists DATES;
create temporary table DATES (AdherenceDates date, WhichSaturday int,
WhichFifthSaturday int);
create temporary table DATES1 (AdherenceDates date, WhichSaturday int);
create temporary table DATES2 (FifthSaturdayDates date, WhichFifthSaturday
int auto_increment, primary key (WhichFifthSaturday));
insert into DATES1 (AdherenceDates, WhichSaturday)
select
a.Date as AdherenceDates,
case
when day(adddate(a.date,(7-dayofweek(a.date)))) <= 7
then 1
when day(adddate(a.date,(7-dayofweek(a.date)))) <= 14
then 2
when day(adddate(a.date,(7-dayofweek(a.date)))) <= 21
then 3
when day(adddate(a.date,(7-dayofweek(a.date)))) <= 28
then 4
when day(adddate(a.date,(7-dayofweek(a.date)))) > 28
then 5
end as WhichSaturday
from
(select
curdate() - interval (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a)) day
as Date
from (
select 0 as a union all select 1 union all select 2 union all select 3
union all select 4 union all select 5 union all select 6 union all select 7
union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union
all select 3 union all select 4 union all select 5 union all select 6 union
all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union
all select 3 union all select 4 union all select 5 union all select 6 union
all select 7 union all select 8 union all select 9) as c
cross join (select 0 as a union all select 1 union all select 2 union
all select 3 union all select 4 union all select 5 union all select 6 union
all select 7 union all select 8 union all select 9) as d
) as a
where dayofweek(a.Date) <> 1
and a.Date >= '2017-01-01'
order by a.Date asc
;
insert into DATES2 (FifthSaturdayDates)
select
a.Date as AdherenceDates
from
(select
curdate() - interval (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a)) day
as Date
from (
select 0 as a union all select 1 union all select 2 union all select 3
union all select 4 union all select 5 union all select 6 union all select 7
union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union
all select 3 union all select 4 union all select 5 union all select 6 union
all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union
all select 3 union all select 4 union all select 5 union all select 6 union
all select 7 union all select 8 union all select 9) as c
cross join (select 0 as a union all select 1 union all select 2 union
all select 3 union all select 4 union all select 5 union all select 6 union
all select 7 union all select 8 union all select 9) as d
) as a
where dayofweek(a.Date) = 7
and a.Date >= '2017-01-01'
and day(a.Date) > 28
order by a.date asc;
insert into DATES (AdherenceDates, WhichSaturday, WhichFifthSaturday)
select
DATES1.AdherenceDates,
DATES1.WhichSaturday,
DATES2.WhichFifthSaturday
from
DATES1
left join
DATES2
on DATES1.AdherenceDates = DATES2.FifthSaturdayDates;
drop temporary tables DATES1, DATES2;
select * from DATES
order by AdherenceDates asc;