MySQL 查询以捕获事件之间的工作时间
MySQL query to capture the working time between events
我正在尝试创建一个查询来捕获事件发生所需的工作时间。在下面的数据中,我想显示帐户从 ACTIVATED 变为 DEACTIVATED 所需的工作时间。
ENCODEDKEY TRANSACTIONID LOANPRODUCTKEY TIMESTAMP TYPE
1 2067 aa1 2015/02/06 15:29:00 LOAN_PRODUCT_ACTIVATED
2 2162 aa1 2015/02/16 14:07:00 LOAN_PRODUCT_EDITED
3 2666 aa1 2015/02/16 15:29:00 LOAN_PRODUCT_DEACTIVATED
4 3456 aa2 2015/03/06 12:01:00 LOAN_PRODUCT_ACTIVATED
5 3478 aa2 2015/03/08 13:15:00 LOAN_PRODUCT_EDITED
6 3908 aa2 2015/03/18 13:15:00 LOAN_PRODUCT_DEACTIVATED
所以结果会是这样的
LOANPRODUCTKEY TIME
aa1 24:00:00
aa2 12:00:00
(我知道这些数字是错误的!)
我也需要它只考虑工作时间(即早上 9 点到下午 5 点)这可能吗?
感谢任何能帮助我的人。
更新。 非常感谢到目前为止提供帮助的人!
所以我设法创建了一个查询,该查询将 return 每个 loanproductkey 的激活和停用打字机的正确日期。但是,我仍在努力计算两个计算日期之间的工作时间。我的查询如下:
SELECT
att.LOANPRODUCTKEY
,sub1.time_activated
,sub2.time_deactivated
from
activity att
left join (select
min(att.TIMESTAMP) as time_activated
,att.loanproductkey
from
activity att
where
att.`TYPE` = "LOAN_PRODUCT_ACTIVATED"
group by
att.LOANPRODUCTKEY) AS sub1
ON att.LOANPRODUCTKEY = sub1.LOANPRODUCTKEY
left join
(select
max(att.timestamp) as time_deactivated
,att.LOANPRODUCTKEY
from
activity att
where
att.`TYPE` = "LOAN_PRODUCT_DEACTIVATED"
group by
att.LOANPRODUCTKEY) AS sub2
ON att.LOANPRODUCTKEY = sub2.LOANPRODUCTKEY
group by
att.loanproductkey
好的,所以我认为下面的查询应该可以工作,尽管它可能可以进行很多调整。我猜也很有可能做得更聪明:)
逻辑如下:
首先,它使用数字 table 为每个 loanproductkey 生成开始日期和结束日期之间的日期序列(这是在派生的 table 中完成的)。
然后它加入这个table并计算开始和结束之间的整个工作日数(不包括)并将这个(乘以240得到分钟数)添加到分钟数这是开始天数时间和 17:00 之间的差异,以及 09:00 和结束天数时间之间的分钟差异。
所以计算是这样的:
(minutes from start time of first day to 17:00) -- eg. '17:00:00'-'15:29:00'
+
(minutes from 09:00 to end time of last day) -- eg. '15:29:00'-'09:00'
+
(number of working days between start and end) * 240
您可能需要稍微调整数学,但逻辑应该是合理的。
做出的假设:
周末是 weekday
函数返回的工作日 5 和 6 - 这可能取决于本地服务器设置,我不确定。
存在一个名为 numbers
的 table,其列 num
包含数字 1 到 至少需要覆盖您的范围从开始到结束的最大日期范围。如果你没有这个,我已经在最后描述了你如何创建它。
这会得到如下结果:
LOANPRODUCTKEY total_min total_time (hhh:mm:ss)
aa1 4800 80:00:00
aa2 5834 97:14:00
Sample SQL Fiddle(没有 total_time 列,因为 fiddle 使用 java,它不喜欢小时部分的大值。
SELECT
t_start.LOANPRODUCTKEY
, (
TIMESTAMPDIFF(MINUTE, CAST(t_start.timestamp AS time), CAST('17:00:00' AS time))
+ TIMESTAMPDIFF(MINUTE, CAST('09:00:00' AS time), CAST(t_end.timestamp AS time))
+ COUNT(WEEKDAY(t_start.timestamp) NOT IN (5,6)) * 8 * 60
) AS total_minutes
, SEC_TO_TIME(
TIMESTAMPDIFF(SECOND, CAST(t_start.timestamp AS time), CAST('17:00:00' AS time))
+ TIMESTAMPDIFF(SECOND, CAST('09:00:00' AS time), CAST(t_end.timestamp AS time))
+ COUNT(WEEKDAY(t_start.timestamp) NOT IN (5,6)) * 8 * 60 * 60
) AS total_time
FROM
t t_start
JOIN
t t_end ON t_start.LOANPRODUCTKEY = t_end.LOANPRODUCTKEY
JOIN
(
SELECT
ts.LOANPRODUCTKEY
, DATE(DATE_ADD(ts.timestamp,INTERVAL num DAY)) AS datesSeries
FROM
t ts
JOIN
t te ON ts.LOANPRODUCTKEY = te.LOANPRODUCTKEY
CROSS JOIN
numbers r
WHERE
num < DATEDIFF(te.timestamp, ts.timestamp)
AND
ts.TYPE = 'LOAN_PRODUCT_ACTIVATED'
AND
te.TYPE = 'LOAN_PRODUCT_DEACTIVATED'
) dates ON t_start.LOANPRODUCTKEY = dates.LOANPRODUCTKEY
WHERE
t_start.TYPE = 'LOAN_PRODUCT_ACTIVATED' AND t_end.TYPE = 'LOAN_PRODUCT_DEACTIVATED'
GROUP BY
t_start.LOANPRODUCTKEY, t_start.TIMESTAMP, t_end.TIMESTAMP
ORDER BY
t_start.LOANPRODUCTKEY;
如果您还没有 suitable table 的数字序列涵盖开始日期和结束日期之间的最大天数,您可以创建一个 table使用下面的查询填充数字 1-1000,我从 this answer.
中获取
CREATE TABLE numbers (num int primary key);
INSERT INTO numbers
SELECT SEQ.SeqValue
FROM (
SELECT (HUNDREDS.SeqValue + TENS.SeqValue + ONES.SeqValue) SeqValue
FROM (
SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue UNION ALL
SELECT 2 SeqValue UNION ALL SELECT 3 SeqValue UNION ALL
SELECT 4 SeqValue UNION ALL SELECT 5 SeqValue UNION ALL
SELECT 6 SeqValue UNION ALL SELECT 7 SeqValue UNION ALL
SELECT 8 SeqValue UNION ALL SELECT 9 SeqValue
) ONES
CROSS JOIN (
SELECT 0 SeqValue UNION ALL SELECT 10 SeqValue UNION ALL
SELECT 20 SeqValue UNION ALL SELECT 30 SeqValue UNION ALL
SELECT 40 SeqValue UNION ALL SELECT 50 SeqValue UNION ALL
SELECT 60 SeqValue UNION ALL SELECT 70 SeqValue UNION ALL
SELECT 80 SeqValue UNION ALL SELECT 90 SeqValue
) TENS
CROSS JOIN (
SELECT 0 SeqValue UNION ALL SELECT 100 SeqValue UNION ALL
SELECT 200 SeqValue UNION ALL SELECT 300 SeqValue UNION ALL
SELECT 400 SeqValue UNION ALL SELECT 500 SeqValue UNION ALL
SELECT 600 SeqValue UNION ALL SELECT 700 SeqValue UNION ALL
SELECT 800 SeqValue UNION ALL SELECT 900 SeqValue
) HUNDREDS
) SEQ WHERE SEQ.SeqValue > 0;
我正在尝试创建一个查询来捕获事件发生所需的工作时间。在下面的数据中,我想显示帐户从 ACTIVATED 变为 DEACTIVATED 所需的工作时间。
ENCODEDKEY TRANSACTIONID LOANPRODUCTKEY TIMESTAMP TYPE
1 2067 aa1 2015/02/06 15:29:00 LOAN_PRODUCT_ACTIVATED
2 2162 aa1 2015/02/16 14:07:00 LOAN_PRODUCT_EDITED
3 2666 aa1 2015/02/16 15:29:00 LOAN_PRODUCT_DEACTIVATED
4 3456 aa2 2015/03/06 12:01:00 LOAN_PRODUCT_ACTIVATED
5 3478 aa2 2015/03/08 13:15:00 LOAN_PRODUCT_EDITED
6 3908 aa2 2015/03/18 13:15:00 LOAN_PRODUCT_DEACTIVATED
所以结果会是这样的
LOANPRODUCTKEY TIME
aa1 24:00:00
aa2 12:00:00
(我知道这些数字是错误的!)
我也需要它只考虑工作时间(即早上 9 点到下午 5 点)这可能吗?
感谢任何能帮助我的人。
更新。 非常感谢到目前为止提供帮助的人!
所以我设法创建了一个查询,该查询将 return 每个 loanproductkey 的激活和停用打字机的正确日期。但是,我仍在努力计算两个计算日期之间的工作时间。我的查询如下:
SELECT
att.LOANPRODUCTKEY
,sub1.time_activated
,sub2.time_deactivated
from
activity att
left join (select
min(att.TIMESTAMP) as time_activated
,att.loanproductkey
from
activity att
where
att.`TYPE` = "LOAN_PRODUCT_ACTIVATED"
group by
att.LOANPRODUCTKEY) AS sub1
ON att.LOANPRODUCTKEY = sub1.LOANPRODUCTKEY
left join
(select
max(att.timestamp) as time_deactivated
,att.LOANPRODUCTKEY
from
activity att
where
att.`TYPE` = "LOAN_PRODUCT_DEACTIVATED"
group by
att.LOANPRODUCTKEY) AS sub2
ON att.LOANPRODUCTKEY = sub2.LOANPRODUCTKEY
group by
att.loanproductkey
好的,所以我认为下面的查询应该可以工作,尽管它可能可以进行很多调整。我猜也很有可能做得更聪明:)
逻辑如下:
首先,它使用数字 table 为每个 loanproductkey 生成开始日期和结束日期之间的日期序列(这是在派生的 table 中完成的)。
然后它加入这个table并计算开始和结束之间的整个工作日数(不包括)并将这个(乘以240得到分钟数)添加到分钟数这是开始天数时间和 17:00 之间的差异,以及 09:00 和结束天数时间之间的分钟差异。
所以计算是这样的:
(minutes from start time of first day to 17:00) -- eg. '17:00:00'-'15:29:00'
+
(minutes from 09:00 to end time of last day) -- eg. '15:29:00'-'09:00'
+
(number of working days between start and end) * 240
您可能需要稍微调整数学,但逻辑应该是合理的。
做出的假设:
周末是
weekday
函数返回的工作日 5 和 6 - 这可能取决于本地服务器设置,我不确定。存在一个名为
numbers
的 table,其列num
包含数字 1 到 至少需要覆盖您的范围从开始到结束的最大日期范围。如果你没有这个,我已经在最后描述了你如何创建它。
这会得到如下结果:
LOANPRODUCTKEY total_min total_time (hhh:mm:ss)
aa1 4800 80:00:00
aa2 5834 97:14:00
Sample SQL Fiddle(没有 total_time 列,因为 fiddle 使用 java,它不喜欢小时部分的大值。
SELECT
t_start.LOANPRODUCTKEY
, (
TIMESTAMPDIFF(MINUTE, CAST(t_start.timestamp AS time), CAST('17:00:00' AS time))
+ TIMESTAMPDIFF(MINUTE, CAST('09:00:00' AS time), CAST(t_end.timestamp AS time))
+ COUNT(WEEKDAY(t_start.timestamp) NOT IN (5,6)) * 8 * 60
) AS total_minutes
, SEC_TO_TIME(
TIMESTAMPDIFF(SECOND, CAST(t_start.timestamp AS time), CAST('17:00:00' AS time))
+ TIMESTAMPDIFF(SECOND, CAST('09:00:00' AS time), CAST(t_end.timestamp AS time))
+ COUNT(WEEKDAY(t_start.timestamp) NOT IN (5,6)) * 8 * 60 * 60
) AS total_time
FROM
t t_start
JOIN
t t_end ON t_start.LOANPRODUCTKEY = t_end.LOANPRODUCTKEY
JOIN
(
SELECT
ts.LOANPRODUCTKEY
, DATE(DATE_ADD(ts.timestamp,INTERVAL num DAY)) AS datesSeries
FROM
t ts
JOIN
t te ON ts.LOANPRODUCTKEY = te.LOANPRODUCTKEY
CROSS JOIN
numbers r
WHERE
num < DATEDIFF(te.timestamp, ts.timestamp)
AND
ts.TYPE = 'LOAN_PRODUCT_ACTIVATED'
AND
te.TYPE = 'LOAN_PRODUCT_DEACTIVATED'
) dates ON t_start.LOANPRODUCTKEY = dates.LOANPRODUCTKEY
WHERE
t_start.TYPE = 'LOAN_PRODUCT_ACTIVATED' AND t_end.TYPE = 'LOAN_PRODUCT_DEACTIVATED'
GROUP BY
t_start.LOANPRODUCTKEY, t_start.TIMESTAMP, t_end.TIMESTAMP
ORDER BY
t_start.LOANPRODUCTKEY;
如果您还没有 suitable table 的数字序列涵盖开始日期和结束日期之间的最大天数,您可以创建一个 table使用下面的查询填充数字 1-1000,我从 this answer.
中获取CREATE TABLE numbers (num int primary key);
INSERT INTO numbers
SELECT SEQ.SeqValue
FROM (
SELECT (HUNDREDS.SeqValue + TENS.SeqValue + ONES.SeqValue) SeqValue
FROM (
SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue UNION ALL
SELECT 2 SeqValue UNION ALL SELECT 3 SeqValue UNION ALL
SELECT 4 SeqValue UNION ALL SELECT 5 SeqValue UNION ALL
SELECT 6 SeqValue UNION ALL SELECT 7 SeqValue UNION ALL
SELECT 8 SeqValue UNION ALL SELECT 9 SeqValue
) ONES
CROSS JOIN (
SELECT 0 SeqValue UNION ALL SELECT 10 SeqValue UNION ALL
SELECT 20 SeqValue UNION ALL SELECT 30 SeqValue UNION ALL
SELECT 40 SeqValue UNION ALL SELECT 50 SeqValue UNION ALL
SELECT 60 SeqValue UNION ALL SELECT 70 SeqValue UNION ALL
SELECT 80 SeqValue UNION ALL SELECT 90 SeqValue
) TENS
CROSS JOIN (
SELECT 0 SeqValue UNION ALL SELECT 100 SeqValue UNION ALL
SELECT 200 SeqValue UNION ALL SELECT 300 SeqValue UNION ALL
SELECT 400 SeqValue UNION ALL SELECT 500 SeqValue UNION ALL
SELECT 600 SeqValue UNION ALL SELECT 700 SeqValue UNION ALL
SELECT 800 SeqValue UNION ALL SELECT 900 SeqValue
) HUNDREDS
) SEQ WHERE SEQ.SeqValue > 0;