以下显示的以下数据子集是我必须在RecOn与RecOFF配对方面找到解决方案的一小部分,或者允许RecON或RecOFF显示空/空记录。 数据集中可能的组合集是可能的,我也提出了解决方案。下面是示例数据的导出,然后是我迄今为止创建的解决方案,这在所有示例中都不够。
从长远来看,我想为此创建一个更简单的功能,因为数据必须从原始数据中规范化,除此之外我不能使用除MySQL之外的任何其他语言,除非它真的不可能。
理论选项
Rec ON/OFF | RecordTime
RecON | 8:00:00
RecOFF | 9:00:00
RecOFF | 10:00:00
RecON | 11:00:00
RecOFF | 12:00:00
RecON | 14:00:00
RecON | 15:00:00
这应该进入
TimeRecON | TimeRecOFF
8:00 | 9:00
null | 10:00
11:00 | 12:00
14:00 | null
15:00 | null
示例数据:
INSERT INTO `tbltest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (4865,'Make-e-plan','BANK','2017-08-26 16:23:47','RecON','16:23:53');
INSERT INTO `tbltest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (4878,'Make-e-plan','BANK','2017-08-26 16:23:47','RecOFF','17:33:24');
INSERT INTO `tbltest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (4890,'Make-e-plan','BANK','2017-08-26 16:23:47','RecOFF','18:50:07');
INSERT INTO `tblTest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (352,'Baobab','DILA','2017-08-16 07:55:52','RecON','08:58:45');
INSERT INTO `tblTest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (377,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:50:42');
INSERT INTO `tblTest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (379,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:51:13');
INSERT INTO `tblTest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (382,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:56:36');
INSERT INTO `tblTest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (384,'Baobab','DILA','2017-08-16 07:55:52','RecON','10:59:58');
INSERT INTO `tblTest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (396,'Baobab','DILA','2017-08-16 07:55:52','RecON','11:20:45');
INSERT INTO `tblTest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (412,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','12:04:04');
我的查询到目前为止
SELECT `id`, `GroupName`, `Observer`, `ArrivalTime`, `Behaviour`, `RecOnTime`, `RecOffTime`, `PreviousContext`, `PreviousBehaviour`, `PreviousID`
FROM (
SELECT `id`, `GroupName`, `Observer`, `ArrivalTime`, `Behaviour`, `RecordTime` `RecOfftime`, -- note that the recordtime is RecOFF here
@lastContext `PreviousContext`,
@lastBehaviour `PreviousBehaviour`, @lastid `PreviousID`,
CASE
WHEN @lastBehaviour <> `Behaviour` -- The previous record has to be RecON (this statement could be re-written to = "RecON")
AND `Behaviour` = "RecOFF"
THEN @lastRecordTime
ELSE
CASE WHEN @lastBehaviour = 'RecON' AND `Behaviour`= 'RecON' -- IF there are two RecON instances after each other without a RecOFF then put the previous instance as first RecON
THEN @lastRecordTime
ELSE "00:00:00" -- IF RecOn and RecOFF do not match enter 0
END
END
AS `RecOnTime`,
@lastid := `id`,
@lastRecordTime := TIME(`RecordTime`),
@lastBehaviour := `Behaviour`,
FROM `KMP_adlib_testing`.`tblAdlibRaw`
WHERE `Behaviour` IN ('RecOn', 'RecOFF') -- This pre-filters for only RecON and RecOFF behaviours
AND `Observer` = @varObserver AND `GroupName` = @varGroupName AND ArrivalTime = @varArrivalTime
) as `tmp`
WHERE RecOnTime <> "00:00:00" -- This filters all records where there is no RecON for the behaviours.. This could be re-entered as where the Context is null????
;
我提供的示例数据的预期解决方案是:
Group | Observer | RecON | RecOFF
Baobab | DILA | 08:58:45 | 10:50:42
Baobab | DILA | null | 10:51:13
Baobab | DILA | null | 10:56:36
Baobab | DILA | 10:59:58 | null
Baobab | DILA | 11:20:45 | 12:04:04
Make-e-plan | BANK | 16:23:53 | 17:33:24
Make-e-plan | BANK | null | 18:50:07
基于Used_By_Already响应的查询的工作版本。 我觉得仍然可以进行优化。
select groupname
, observer
, ArrivalTime
, TimeOn
, case INNER2.rownum_difference WHEN 1 THEN INNER2.TimeOff ELSE NULL END AS TIMEOFF
FROM (
SELECT
groupname
, observer
, ArrivalTime
, t1.RecordTime TimeOn
, (SELECT
MIN(t2.RecordTime)
FROM tblAdlibPreProcessing t2
WHERE t2.GroupName = t1.GroupName
AND t2.Observer = t1.Observer
AND t2.Behaviour = 'RecOFF'
AND t2.RecordTime > t1.RecordTime
AND t2.GroupName = @groupname
AND t2.Observer = @observer
AND t2.ArrivalTime = @arrivaltime
)
TimeOff
-- This can remain out
-- , (SELECT id
-- FROM tbltest t3
-- WHERE t3.RecordTime = (SELECT MIN(t2.RecordTime)
-- FROM tblAdlibPreProcessing t2
-- WHERE t2.GroupName = t1.GroupName
-- AND t2.Observer = t1.Observer
-- AND t2.Behaviour = 'RecOFF'
-- AND t2.RecordTime > t1.RecordTime
-- AND t2.GroupName = @groupname
-- AND t2.Observer = @observer
-- AND t2.ArrivalTime = @arrivaltime
-- )
-- ) rownum_time_off
-- , t1.id as rownum_time_on
-- End this can be left out
, (SELECT id
FROM tblAdlibPreProcessing t3
WHERE 1=1
AND t3.GroupName = @groupname
AND t3.Observer = @observer
AND t3.ArrivalTime = @arrivaltime
AND t3.RecordTime = (SELECT MIN(t2.RecordTime)
FROM tblAdlibPreProcessing t2
WHERE t2.GroupName = t1.GroupName
AND t2.Observer = t1.Observer
AND t2.Behaviour = 'RecOFF'
AND t2.RecordTime > t1.RecordTime
AND t2.GroupName = @groupname
AND t2.Observer = @observer
AND t2.ArrivalTime = @arrivaltime
)
) - t1.id as rownum_difference
FROM tblAdlibPreProcessing t1
WHERE Behaviour = 'RecON'
AND t1.GroupName = @groupname
AND t1.Observer = @observer
AND t1.ArrivalTime = @arrivaltime
) INNER2
UNION ALL
SELECT
ou.groupname
, ou.observer
, ou.ArrivalTime
, NULL
, ou.RecordTime
FROM (
-- off_unpaired
SELECT
groupname
, observer
, ArrivalTime
, t1.RecordTime
, (SELECT
MAX(t2.RecordTime)
FROM tblAdlibPreProcessing t2
WHERE t2.GroupName = t1.GroupName
AND t2.Observer = t1.Observer
AND t2.Behaviour = 'RecON'
AND t2.RecordTime < t1.RecordTime)
max_t2_rt
FROM tblAdlibPreProcessing t1
WHERE Behaviour = 'RecOFF'
AND t1.GroupName = @groupname
AND t1.Observer = @observer
AND t1.ArrivalTime = @arrivaltime
) ou
LEFT JOIN (
-- on_off_paired
SELECT
groupname
, observer
, ArrivalTime
, t1.RecordTime TimeOn
, (SELECT
MIN(t2.RecordTime)
FROM tblAdlibPreProcessing t2
WHERE t2.GroupName = t1.GroupName
AND t2.Observer = t1.Observer
AND t2.Behaviour = 'RecOFF'
AND t2.RecordTime > t1.RecordTime
AND t2.GroupName = @groupname
AND t2.Observer = @observer
AND t2.ArrivalTime = @arrivaltime)
TimeOff
FROM tblAdlibPreProcessing t1
WHERE Behaviour = 'RecON'
) oop ON ou.groupname = oop.groupname
AND ou.observer = oop.observer
AND ou.ArrivalTime = oop.ArrivalTime
AND ou.max_t2_rt = oop.TimeOn
AND ou.RecordTime = oop.TimeOff
WHERE oop.groupname IS NULL
ORDER BY 1, 2, 3, 4, 5;
答案 0 :(得分:2)
下面我展示了2个查询。第一个是&#34;临时&#34;一步,我显示这个,这样你就可以看到它的结果。第二个查询添加了一个逻辑,用于删除TimeOff
列的重复并替换那些带有NULL的列。
虽然您提供了样本数据(谢谢),但您不会根据该数据显示expected result
。所以在某种程度上,我猜测你真正期望的细节,希望它能够接近。
create table `tbltest` (`id` int,`GroupName` varchar(40),`Observer` varchar(40),`ArrivalTime` time,`Behaviour` varchar(20),`RecordTime` time);
INSERT INTO `tbltest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (4865,'Make-e-plan','BANK','2017-08-26 16:23:47','RecON','16:23:53') , (4878,'Make-e-plan','BANK','2017-08-26 16:23:47','RecOFF','17:33:24') , (4890,'Make-e-plan','BANK','2017-08-26 16:23:47','RecOFF','18:50:07') , (352,'Baobab','DILA','2017-08-16 07:55:52','RecON','08:58:45') , (377,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:50:42') , (379,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:51:13') , (382,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:56:36') , (384,'Baobab','DILA','2017-08-16 07:55:52','RecON','10:59:58') , (396,'Baobab','DILA','2017-08-16 07:55:52','RecON','11:20:45') , (412,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','12:04:04');
select groupname,observer,ArrivalTime, t1.RecordTime , (select min(t2.RecordTime) from tbltest t2 where t2.GroupName = t1.GroupName and t2.Observer = t1.Observer and t2.Behaviour = 'RecOFF' and t2.RecordTime > t1.RecordTime) min_t2_rt from tbltest t1 where Behaviour = 'RecON' union all select groupname,observer,ArrivalTime, t1.RecordTime , (select min(t2.RecordTime) from tbltest t2 where t2.GroupName = t1.GroupName and t2.Observer = t1.Observer and t2.Behaviour = 'RecON' and t2.RecordTime > t1.RecordTime) min_t2_rt from tbltest t1 where Behaviour = 'RecOFF' order by 1,2,3,4
groupname | observer | ArrivalTime | RecordTime | min_t2_rt :---------- | :------- | :---------- | :--------- | :-------- Baobab | DILA | 07:55:52 | 08:58:45 | 10:50:42 Baobab | DILA | 07:55:52 | 10:50:42 | 10:59:58 Baobab | DILA | 07:55:52 | 10:51:13 | 10:59:58 Baobab | DILA | 07:55:52 | 10:56:36 | 10:59:58 Baobab | DILA | 07:55:52 | 10:59:58 | 12:04:04 Baobab | DILA | 07:55:52 | 11:20:45 | 12:04:04 Baobab | DILA | 07:55:52 | 12:04:04 | null Make-e-plan | BANK | 16:23:47 | 16:23:53 | 17:33:24 Make-e-plan | BANK | 16:23:47 | 17:33:24 | null Make-e-plan | BANK | 16:23:47 | 18:50:07 | null
SELECT groupname , observer , ArrivalTime , TimeOn , IF(@prev_value=TimeOff, NULL, TimeOff) TimeOff , @prev_value := TimeOff x FROM ( SELECT groupname , observer , ArrivalTime , t1.RecordTime TimeOn , ( SELECT MIN(t2.RecordTime) FROM tbltest t2 WHERE t2.GroupName = t1.GroupName AND t2.Observer = t1.Observer AND t2.Behaviour = 'RecOFF' AND t2.RecordTime > t1.RecordTime ) TimeOff FROM tbltest t1 WHERE Behaviour = 'RecON' UNION ALL SELECT groupname , observer , ArrivalTime , t1.RecordTime TimeOn , ( SELECT MIN(t2.RecordTime) FROM tbltest t2 WHERE t2.GroupName = t1.GroupName AND t2.Observer = t1.Observer AND t2.Behaviour = 'RecON' AND t2.RecordTime > t1.RecordTime ) TimeOff FROM tbltest t1 WHERE Behaviour = 'RecOFF' ORDER BY groupname , observer , ArrivalTime , TimeOn ) d CROSS JOIN (SELECT @row_num :=1, @prev_value :='00:00:00') vars
groupname | observer | ArrivalTime | TimeOn | TimeOff | x :---------- | :------- | :---------- | :------- | :------- | :------- Baobab | DILA | 07:55:52 | 08:58:45 | 10:50:42 | 10:50:42 Baobab | DILA | 07:55:52 | 10:50:42 | 10:59:58 | 10:59:58 Baobab | DILA | 07:55:52 | 10:51:13 | null | 10:59:58 Baobab | DILA | 07:55:52 | 10:56:36 | null | 10:59:58 Baobab | DILA | 07:55:52 | 10:59:58 | 12:04:04 | 12:04:04 Baobab | DILA | 07:55:52 | 11:20:45 | null | 12:04:04 Baobab | DILA | 07:55:52 | 12:04:04 | null | null Make-e-plan | BANK | 16:23:47 | 16:23:53 | 17:33:24 | 17:33:24 Make-e-plan | BANK | 16:23:47 | 17:33:24 | null | null Make-e-plan | BANK | 16:23:47 | 18:50:07 | null | null
dbfiddle(mariadb_10.2)here
顺便说一下,我没有按照原样查询#34;因此我无法比较结果。
哦,当MySQL v8.x确实上街时,它支持LAG() OVER
和LEAD() OVER
等窗口函数,那么这个查询将更容易编写。如果您碰巧使用MariaDB或预发布MySQL 8.x,您应该尝试使用这些窗口函数。我使用的dbfiddle确实支持这些功能,如果你想&#34;尝试它&#34;
答案 1 :(得分:1)
我现在添加了一个不同的答案,即预期结果可用。我认为这更接近了。我相信它可以像我之前的版本一样进行改进,但是(现在)已经没时间添加了。
在此解决方案方法中,我使用WITH
(公用表表达式),因此在支持WITH
之前,还有第二个MySQL版本变体:
create table `tbltest` (`id` int,`GroupName` varchar(40),`Observer` varchar(40),`ArrivalTime` time,`Behaviour` varchar(20),`RecordTime` time);
INSERT INTO `tbltest` (`id`,`GroupName`,`Observer`,`ArrivalTime`,`Behaviour`,`RecordTime`) VALUES (4865,'Make-e-plan','BANK','2017-08-26 16:23:47','RecON','16:23:53') , (4878,'Make-e-plan','BANK','2017-08-26 16:23:47','RecOFF','17:33:24') , (4890,'Make-e-plan','BANK','2017-08-26 16:23:47','RecOFF','18:50:07') , (352,'Baobab','DILA','2017-08-16 07:55:52','RecON','08:58:45') , (377,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:50:42') , (379,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:51:13') , (382,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','10:56:36') , (384,'Baobab','DILA','2017-08-16 07:55:52','RecON','10:59:58') , (396,'Baobab','DILA','2017-08-16 07:55:52','RecON','11:20:45') , (412,'Baobab','DILA','2017-08-16 07:55:52','RecOFF','12:04:04');
使用with
WITH on_off_paired AS ( SELECT groupname , observer , ArrivalTime , t1.RecordTime TimeOn , (SELECT MIN(t2.RecordTime) FROM tbltest t2 WHERE t2.GroupName = t1.GroupName AND t2.Observer = t1.Observer AND t2.Behaviour = 'RecOFF' AND t2.RecordTime > t1.RecordTime) TimeOff FROM tbltest t1 WHERE Behaviour = 'RecON' ) , off_unpaired AS ( SELECT groupname , observer , ArrivalTime , t1.RecordTime , (SELECT MAX(t2.RecordTime) FROM tbltest t2 WHERE t2.GroupName = t1.GroupName AND t2.Observer = t1.Observer AND t2.Behaviour = 'RecON' AND t2.RecordTime < t1.RecordTime) max_t2_rt FROM tbltest t1 WHERE Behaviour = 'RecOFF' ) SELECT groupname , observer , ArrivalTime , TimeOn , TimeOff FROM on_off_paired UNION ALL SELECT ou.groupname , ou.observer , ou.ArrivalTime , NULL , ou.RecordTime FROM off_unpaired ou LEFT JOIN on_off_paired oop ON ou.groupname = oop.groupname AND ou.observer = oop.observer AND ou.ArrivalTime = oop.ArrivalTime AND ou.max_t2_rt = oop.TimeOn AND ou.RecordTime = oop.TimeOff WHERE oop.groupname IS NULL ORDER BY 1, 2, 3, 5;
groupname | observer | ArrivalTime | TimeOn | TimeOff :---------- | :------- | :---------- | :------- | :------- Baobab | DILA | 07:55:52 | 08:58:45 | 10:50:42 Baobab | DILA | 07:55:52 | null | 10:51:13 Baobab | DILA | 07:55:52 | null | 10:56:36 Baobab | DILA | 07:55:52 | 11:20:45 | 12:04:04 Baobab | DILA | 07:55:52 | 10:59:58 | 12:04:04 Make-e-plan | BANK | 16:23:47 | 16:23:53 | 17:33:24 Make-e-plan | BANK | 16:23:47 | null | 18:50:07
没有with
-- where WITH is unavailable SELECT groupname , observer , ArrivalTime , TimeOn , TimeOff FROM ( -- on_off_paired SELECT groupname , observer , ArrivalTime , t1.RecordTime TimeOn , (SELECT MIN(t2.RecordTime) FROM tbltest t2 WHERE t2.GroupName = t1.GroupName AND t2.Observer = t1.Observer AND t2.Behaviour = 'RecOFF' AND t2.RecordTime > t1.RecordTime) TimeOff FROM tbltest t1 WHERE Behaviour = 'RecON' ) D1 UNION ALL SELECT ou.groupname , ou.observer , ou.ArrivalTime , NULL , ou.RecordTime FROM ( -- off_unpaired SELECT groupname , observer , ArrivalTime , t1.RecordTime , (SELECT MAX(t2.RecordTime) FROM tbltest t2 WHERE t2.GroupName = t1.GroupName AND t2.Observer = t1.Observer AND t2.Behaviour = 'RecON' AND t2.RecordTime < t1.RecordTime) max_t2_rt FROM tbltest t1 WHERE Behaviour = 'RecOFF' ) ou LEFT JOIN ( -- on_off_paired SELECT groupname , observer , ArrivalTime , t1.RecordTime TimeOn , (SELECT MIN(t2.RecordTime) FROM tbltest t2 WHERE t2.GroupName = t1.GroupName AND t2.Observer = t1.Observer AND t2.Behaviour = 'RecOFF' AND t2.RecordTime > t1.RecordTime) TimeOff FROM tbltest t1 WHERE Behaviour = 'RecON' ) oop ON ou.groupname = oop.groupname AND ou.observer = oop.observer AND ou.ArrivalTime = oop.ArrivalTime AND ou.max_t2_rt = oop.TimeOn AND ou.RecordTime = oop.TimeOff WHERE oop.groupname IS NULL ORDER BY 1, 2, 3, 5;
groupname | observer | ArrivalTime | TimeOn | TimeOff :---------- | :------- | :---------- | :------- | :------- Baobab | DILA | 07:55:52 | 08:58:45 | 10:50:42 Baobab | DILA | 07:55:52 | null | 10:51:13 Baobab | DILA | 07:55:52 | null | 10:56:36 Baobab | DILA | 07:55:52 | 11:20:45 | 12:04:04 Baobab | DILA | 07:55:52 | 10:59:58 | 12:04:04 Make-e-plan | BANK | 16:23:47 | 16:23:53 | 17:33:24 Make-e-plan | BANK | 16:23:47 | null | 18:50:07
dbfiddle here