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.Start
、Authorization.End
、Authorization.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查询返回超出范围内允许数量的记录的主要内容,如果未能解决你的问题,请参考以下文章
将 varchar 数据类型转换为 datetime 数据类型导致 SQL 查询中的值超出范围