sql >> データベース >  >> RDS >> Mysql

MySQL:重複する期間を2回カウントせずに日時を合計する

    わかりました。本番環境で使用する前に、あらゆる方法でこれをテストすることを強くお勧めします。特に、1つの期間に複数のオーバーラップがある場合に何が起こるかをテストしてください。

    このクエリが行うことは、各期間の期間と、より高いIDを持つ他の期間とどの程度の重複が存在するかを計算することです。

    select
        t1.id,
        t1.start_time,
        t1.end_time,
        t1.end_time - t1.start_time as duration,
        sum(
              if(t2.start_time <  t1.start_time and t2.end_time >  t1.end_time  , t1.end_time - t1.start_time, 0) -- t2 completely around t1
            + if(t2.start_time >= t1.start_time and t2.end_time <= t1.end_time  , t2.end_time - t2.start_time, 0) -- t2 completely within t1
            + if(t2.start_time <  t1.start_time and t2.end_time >  t1.start_time and t2.end_time   < t1.end_time  , t2.end_time - t1.start_time, 0) -- t2 starts before t1 starts and overlaps partially
            + if(t2.start_time <  t1.end_time   and t2.end_time >  t1.end_time   and t2.start_time > t1.start_time, t1.end_time - t2.start_time, 0) -- t2 starts before t1 ends and overlaps partially
        ) as overlap
    from
        times t1
        left join times t2 on
            t2.id > t1.id --  t2.id is greater than t1.id
            and (
                   (t2.start_time <  t1.start_time and t2.end_time >  t1.end_time  ) -- t2 completely around t1
                or (t2.start_time >= t1.start_time and t2.end_time <= t1.end_time  ) -- t2 completely within t1
                or (t2.start_time <  t1.start_time and t2.end_time >  t1.start_time) -- t2 starts before t1 starts and overlaps
                or (t2.start_time <  t1.end_time   and t2.end_time >  t1.end_time  ) -- t2 starts before t1 ends and overlaps
            )
    group by
        t1.id
    

    つまり、最終的に必要なのはこれです:

    select
        sum(t.duration) - sum(t.overlap) as filtered_duration
    from
        (
            OTHER QUERY HERE
        ) as t
    

    したがって、最終的には次のクエリがあります:

    select
        sum(t.duration) - sum(t.overlap) as filtered_duration
    from
        (
            select
                t1.id,
                t1.start_time,
                t1.end_time,
                t1.end_time - t1.start_time as duration,
                sum(
                      if(t2.start_time <  t1.start_time and t2.end_time >  t1.end_time  , t1.end_time - t1.start_time, 0) -- t2 completely around t1
                    + if(t2.start_time >= t1.start_time and t2.end_time <= t1.end_time  , t2.end_time - t2.start_time, 0) -- t2 completely within t1
                    + if(t2.start_time <  t1.start_time and t2.end_time >  t1.start_time and t2.end_time   < t1.end_time  , t2.end_time - t1.start_time, 0) -- t2 starts before t1 starts and overlaps partially
                    + if(t2.start_time <  t1.end_time   and t2.end_time >  t1.end_time   and t2.start_time > t1.start_time, t1.end_time - t2.start_time, 0) -- t2 starts before t1 ends and overlaps partially
                ) as overlap
            from
                times t1
                left join times t2 on
                    t2.id > t1.id --  t2.id is greater than t1.id
                    and (
                           (t2.start_time <  t1.start_time and t2.end_time >  t1.end_time  ) -- t2 completely around t1
                        or (t2.start_time >= t1.start_time and t2.end_time <= t1.end_time  ) -- t2 completely within t1
                        or (t2.start_time <  t1.start_time and t2.end_time >  t1.start_time) -- t2 starts before t1 starts and overlaps
                        or (t2.start_time <  t1.end_time   and t2.end_time >  t1.end_time  ) -- t2 starts before t1 ends and overlaps
                    )
            group by
                t1.id
        ) as t
    


    1. mysqlの配列変数

    2. SQLServerの既存の列にデフォルトの制約を追加する方法

    3. カーボン日付をmysqlタイムスタンプに変換します。

    4. 有効期限にメールで通知する