我一直在MySQL表上使用TimeDiff来获取两个字段之间的区别,两者都是DateTime格式。这是我正在使用的查询,它也将持续时间限制到今年。
SELECT username, CONCAT(
FLOOR(SUM(HOUR(TIMEDIFF(end_time, start_time)) / 24)), ' days ',
MOD(HOUR(TIMEDIFF(end_time, start_time)), 24), ' hours ',
MINUTE(TIMEDIFF(end_time, start_time)), ' minutes')
AS duration
FROM table
WHERE start_time > CONCAT(YEAR(CURDATE()) -1, '-12-31')
GROUP BY username
我遇到的问题是我一直在努力尝试如何从结果中排除周末。有人可以帮忙吗?
答案 0 :(得分:3)
出于示例的目的,我们使用静态@start
和@end
日期,但实际上您可以使用列名替换它们,并且每行将重新计算所有这些值。
SET @start = '2012-09-30';
SET @end = '2012-11-03';
SELECT
@raw_days := DATEDIFF(@end, @start)+1 'raw_days',
@full_weeks := FLOOR(@raw_days / 7) 'full_weeks',
@odd_days := @raw_days - @full_weeks * 7 'odd_days',
@wday_start := DAYOFWEEK(@start) 'wday_start',
@wday_end := DAYOFWEEK(@end) 'wday_end',
@weekend_intrusion := @wday_start + @odd_days 'weekend_intrusion',
@extra_weekends :=
IF(@wday_start = 1, IF(@odd_days = 0, 0, 1),
IF(@weekend_intrusion > 7, 2,
IF(@weekend_intrusion > 6, 1, 0)
)
) 'extra_weekends',
@total_weekends := @full_weeks * 2 + @extra_weekends 'total_weekends',
@total_workdays := @raw_days - @total_weekends 'total_workdays'
IF
语句归结为:
如果一周从星期日开始,并且没有'奇数'天,则没有额外的周末日。如果是奇数天,则只有1个周末,因为它不可能延伸到星期六,因为这将是一个“完整”的一周。
否则,我们会看到一周的剩余部分是否延续了周日。如果是这样,请添加2个周末。否则,如果该部分进入星期六,则添加1个周末日。其他0。
输出:
+----------+------------+----------+------------+----------+-------------------+----------------+----------------+----------------+
| raw_days | full_weeks | odd_days | wday_start | wday_end | weekend_intrusion | extra_weekends | total_weekends | total_workdays |
+----------+------------+----------+------------+----------+-------------------+----------------+----------------+----------------+
| 34 | 4 | 6 | 1 | 6 | 7 | 1 | 9 | 25 |
+----------+------------+----------+------------+----------+-------------------+----------------+----------------+----------------+
答案 1 :(得分:1)
这应该有效:
SELECT
username,
CONCAT(
FLOOR(
SUM(
UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP(start_time) - 86400 * (
(FLOOR(DATEDIFF(end_time, start_time) / 7) * 2) +
IF(WEEKDAY(end_time) > 4, WEEKDAY(end_time) - 4, 0) +
IF(WEEKDAY(end_time) < WEEKDAY(start_time), 2, 0)
)
) / 86400
),
' days ',
TIME_FORMAT(
SEC_TO_TIME(
SUM(
UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP(start_time) - 86400 * (
(FLOOR(DATEDIFF(end_time, start_time) / 7) * 2) +
IF(WEEKDAY(end_time) > 4, WEEKDAY(end_time) - 4, 0) +
IF(WEEKDAY(end_time) < WEEKDAY(start_time), 2, 0)
)
) % 86400
),
'%H hours %i minutes'
)
) AS duration
FROM table
WHERE start_time > CONCAT(YEAR(CURDATE()) -1, '-12-31')
GROUP BY username;
但它假设start_time
和end_time
在周末期间永远不会下降。
有关工作示例,请参阅http://sqlfiddle.com/#!2/d41d8/3587。
如果您不关心额外的列,则可以将此查询简化为:
SELECT
@diff := SUM(
UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP(start_time) - 86400 * (
(FLOOR(DATEDIFF(end_time, start_time) / 7) * 2) +
IF(WEEKDAY(end_time) > 4, WEEKDAY(end_time) - 4, 0) +
IF(WEEKDAY(end_time) < WEEKDAY(start_time), 2, 0)
)
) AS duration_seconds,
CONCAT(
FLOOR(@diff / 86400),
' days ',
TIME_FORMAT(SEC_TO_TIME(@diff % 86400), '%H hours %i minutes')
) AS duration
FROM table
WHERE start_time > CONCAT(YEAR(CURDATE()) -1, '-12-31')
GROUP BY username;
答案 2 :(得分:0)
继承了我刚刚使用我的日期维度表开发的批量解决方案,它允许在周末期间开始和结束。
Select
f.id, f.dtStart, f.dtEnd,
sec_to_time(
sum(
case
-- don't count weekends
when day_in_week in (6,7)
then 0
-- start and end on same day
when date(f.dtStart) = date(f.dtEnd)
then UNIX_TIMESTAMP(f.dtEnd) - UNIX_TIMESTAMP(f.dtStart)
-- start period
when date(f.dtStart) = dt.date_value
then 24*60*60 - time_to_sec(time(f.dtStart))
-- end period
when date(f.dtEnd) = dt.date_value
then time_to_sec(time(f.dtEnd))
-- middle days
else 24*60*60
end
)
) INT_timediff,
From fact f
join dim_date dt
on dt.date_value between date(f.dtStart) and date(f.dtEnd)
group by f.id, f.dtStart, f.dtEnd