Запрос SQL для возврата записей, превышающих допустимое количество в диапазоне - PullRequest
3 голосов
/ 13 мая 2019

Представьте, что работнику разрешено иметь переменное количество смен в течение определенного периода времени.Мы хотим запросить сдвиги, превышающие разрешенную сумму для любого периода, а также сдвиги вне всех периодов.

Я связал db-fiddle с тестовым запросом.Проблемы здесь:

  1. Для избыточных смен порядок объединенных смен недетерминирован.Я хочу видеть только избыточную смену (2016-05-30 - это 4-я смена в периоде, когда было разрешено только 3 смены).
  2. Я также хочу увидеть 3 смены, которые не были авторизованы ввсе (2019-04-25, 2019-06-02, 2019-06-04).

Я ожидаю, что мне нужно перевернуть запрос (т. е. выбрать из Shift join Authorization) и использовать некоторыесочетание групп по, порядку и лимиту, но я не добился успеха.Любой вклад будет высоко ценится.

CREATE TABLE `Authorization` (
  `AuthorizationId` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `WorkerId` int(10) unsigned NOT NULL,
  `Start` date NOT NULL,
  `End` date NOT NULL,
  `ShiftsAllowed` int(10) unsigned NOT NULL,
  PRIMARY KEY (`AuthorizationId`)
);

CREATE TABLE `Shift` (
  `ShiftId` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `WorkerId` int(10) unsigned NOT NULL,
  `Date_` date NOT NULL,
  PRIMARY KEY (`ShiftId`)
);

INSERT INTO Authorization (WorkerId,Start,End,ShiftsAllowed) VALUES 
(1,'2019-05-01','2019-05-15',2),
(1,'2019-05-16','2019-05-31',3);

INSERT INTO Shift (WorkerId,Date_) VALUES 
(1,'2019-04-25'),
(1,'2019-05-01'),
(1,'2019-05-10'),
(1,'2019-05-16'),
(1,'2019-05-20'),
(1,'2019-05-25'),
(1,'2019-05-30'),
(1,'2019-06-02'),
(1,'2019-06-04');

select 
    Authorization.Start, 
    Authorization.End, 
    Authorization.ShiftsAllowed, 
    count(Shift.Date_), 
    group_concat(Shift.Date_),
    reverse(
      substring_index(
        reverse(group_concat(Shift.Date_)),
        ',',
        count(Shift.Date_) - Authorization.ShiftsAllowed
      )
    )
from Authorization
left join Shift
on
    Shift.WorkerId = Authorization.WorkerId
    and Shift.Date_ between Authorization.Start and Authorization.End
group by Authorization.AuthorizationId
having 
count(Shift.ShiftId) > Authorization.ShiftsAllowed

Просмотр на дб-скрипке

Ответы [ 2 ]

0 голосов
/ 14 мая 2019

Хорошо сделано для обеспечения MCVE.

Для версий старше 8.0 ...

SELECT workerid
     , date_   FROM 
     ( SELECT s.workerid
            , a.authorizationid
            , a.start
            , a.end
            , a.shiftsallowed
            , s.date_
            , CASE WHEN @prev = authorizationid THEN @i:=@i+1 ELSE @i:=1 END i
            , @prev:=authorizationid prev 
         FROM shift s 
         LEFT
         JOIN authorization a 
           ON a.workerid = s.workerid 
          AND s.date_ BETWEEN a.start AND a.end 
         JOIN 
            ( SELECT @prev:=null,@i:=0 ) vars 
        ORDER 
           BY a.authorizationid
            , s.date_
     ) x  WHERE i>shiftsallowed OR authorizationid IS NULL;
0 голосов
/ 13 мая 2019

Поскольку MySQL 5.7 не поддерживает оконную функцию.

Я использовал коррелированный подзапрос вместо него.

Попробуйте это:

select a3.shiftid, a3.workerid, a3.date_ from (
select a2.*, 
(select count(*) 
 from (select s.*, a.start, a.end, a.shiftsallowed
        from Shift s
        left join Authorization a
        on a.workerid = s.workerid
        and s.date_ between a.start and a.end) a1 
        where a1.date_ <= a2.date_ 
        and a1.workerid = a2.workerid and a1.start = a2.start and a1.end  = a2.end) rnk
from (
select s.*, a.start, a.end, a.shiftsallowed
from Shift s
left join Authorization a
on a.workerid = s.workerid
and s.date_ between a.start and a.end )a2)a3
where a3.rnk > a3.shiftsallowed or rnk = 0

Я предлагаю вам выполнить этот запрос, если вы не понимаете ответ.

select s.*, a.start, a.end, a.shiftsallowed
from Shift s
left join Authorization a
on a.workerid = s.workerid
and s.date_ between a.start and a.end 

Затем добавьте столбец ранга - коррелированный подзапрос

Результат теста:

DB-Fiddle

...