1

私は、MySQL テーブルで TimeDiff を使用して、2 つのフィールドの違いを両方とも 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

私が抱えている問題は、週末を結果から除外する方法を見つけるのに苦労していることです。誰でも助けてもらえますか?

4

3 に答える 3

4

例として静的@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 日しかありません。これは、それが「完全な」週であるため、土曜日まで延長できない可能性があるためです。

それ以外の場合は、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 |
+----------+------------+----------+------------+----------+-------------------+----------------+----------------+----------------+
于 2012-11-09T21:42:51.410 に答える
0

これは機能するはずです:

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;
于 2012-11-09T22:10:35.047 に答える