在MySQL中总结重叠日期时间的最有效方法

时间:2017-01-29 17:55:20

标签: mysql algorithm datetime

我正在评估与SO相关的提议解决方案与MySQL中重叠日期时间的总和。我无法找到一个银弹解决方案,所以想知道是否有任何经典/工业级算法程序,或者是否需要开发定制的。

Graphical representation

总计应为8小时(4 + 4)。

通过MySQL提出的解决方案

function final_balance($teacher_id, $aa, $teaching_id=0) {
    $dbo = $this->Attendance->getDataSource();
    $years=$this->Attendance->Student->Year->find('list', array('fields' => array('anno', 'data_from')));
    $filteraa='attendances.start>="'.$years[$aa].'"';
    $this->query('SET @interval_id = 0');
    $this->query('SET @interval_end = \'1970-01-01 00:00:00\'');
    $sql='SELECT 
        MIN(start) as start,
        MAX(end) as end 
        FROM (
            SELECT
               @interval_id := IF(attendances.start > @interval_end, @interval_id + 1, @interval_id) AS interval_id,
               @interval_end := IF(attendances.start < @interval_end, GREATEST(@interval_end, attendances.end), attendances.end) AS interval_end,
               attendances.start,
               attendances.end
             FROM attendances
             INNER JOIN attendance_sheets ON (
                 attendance_sheet_id = attendance_sheets.id AND 
                 attendance_sheets.teacher_id='.$teacher_id.' AND '.$filteraa.' AND 
                 attendance_sheet_status_id = 2 AND 
                 attendance_status_id!=3'.
                 ($teaching_id?' AND attendances.teaching_id IN ('.$teaching_id.')':'').'                    
             )
             ORDER BY attendances.start,attendances.end
        ) intervals GROUP BY interval_id';

    // final query to sum in the temp table
    $finalStatement =array(
        'table' => $dbo->expression('('.$sql.')')->value,
        'alias' => 'Attendance',
        'fields' => array(
            'DATE_FORMAT(start, \'%d/%m/%Y\') as data',
            'DATE_FORMAT(start, \'%m-%Y\') as datamese',
            'DATE(start) as datasql',
            $teacher_id.' AS teacher_id',
            'DAY(start) as giorno',
            'MONTH(start) as mese', 
            'YEAR(start) as anno',
            'SEC_TO_TIME(SUM((TIME_TO_SEC(end) - TIME_TO_SEC(start)))) as ore',
        ),
        'conditions' => array(),
        'limit' => null,
        'group' => array('CONCAT(YEAR(start),MONTH(start))', 'DATE(start) WITH ROLLUP'),
        'order' => null
    );
    $finalQuery= $dbo->buildStatement($finalStatement, $this->Attendance);
    return $this->Attendance->query($dbo->expression($finalQuery)->value);
}

参考

Sum amount of overlapping datetime ranges in MySQL 执行不同的任务

MySQL: sum time ranges exluding overlapping onesMySQL: sum datetimes without counting overlapping periods twice 在我看来,似乎没有考虑所有案例

GeeksForCode: Merge Overlapping Intervals

1 个答案:

答案 0 :(得分:0)

根据具体情况,以下内容可能有用且有效。

创建另一个每小时有一行的表。将表与表一起内连接,同时仅选择新列并重复行。

您可以不断提高分辨率(例如分钟或秒),但这可能会导致代码运行缓慢。