SQL查询返回超出范围内允许数量的记录

Posted

技术标签:

【中文标题】SQL查询返回超出范围内允许数量的记录【英文标题】:SQL Query to return records in excess of allowed amount within range 【发布时间】:2019-09-30 16:00:00 【问题描述】:

想象一个工人被允许在定义的时间段内进行可变数量的轮班。我们希望查询任何时期内超过允许数量的班次以及所有时期外的班次。

我已将 db-fiddle 与测试查询相关联。这里的问题是:

    对于多余的班次,合并班次的顺序是不确定的。我只想看到多余的班次(2016-05-30 是在仅授权 3 个班次的时期内的第 4 个班次)。 我也想看看根本没有授权的3班(2019-04-25、2019-06-02、2019-06-04)。

我希望我需要翻转查询(即从 Shift join Authorization 中选择)并使用 group by、order by 和 limit 的某种组合,但我没有取得任何成功。任何意见将不胜感激。

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

View on db-fiddle

【问题讨论】:

学会正确使用GROUP BY @Eric 你介意描述或展示一个例子吗? Authorization.StartAuthorization.EndAuthorization.ShiftsAllowed 都是非聚合列,必须包含在GROUP BY 中。没有其他 dbms 系统将运行您的代码。即使是较新版本的 mysql 也不会运行您的代码。 【参考方案1】:

由于 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

【讨论】:

【参考方案2】:

提供 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;

【讨论】:

以上是关于SQL查询返回超出范围内允许数量的记录的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 浮点数据类型超出范围

将 varchar 数据类型转换为 datetime 数据类型导致 SQL 查询中的值超出范围

UIImageView 查找超出范围的数量

查询在 MySQL 中有效,但不能通过 Lumen/Laravel - 数值超出范围:1416

索引超出范围但实际上在范围内[关闭]

匹配两个数字文件以超出范围和范围内