Correlate Sequences of Independent Events - Calculate Time Intersection

房东的猫 提交于 2019-12-04 12:42:27
alejandro zuleta

I think this solution requires a CROSS JOIN implementation. The relationship between both tables is Many to Many which implies the creation of a third table that bridges LocationEvents and VehicleStatusEvents tables so I think specifying the relationship in the expression could be easier.

I use a CROSS JOIN between both tables, then filter the results only to get those rows which VehicleID columns are the same in both tables. I am also filtering the rows that VehicleStatusEvents range dates intersects LocationEvents range dates.

Once the filtering is done I am adding a column to calculate the count of days between each intersection. Finally, the measure sums up the days for each VehicleID, ReasonCodeID and LocationID.

In order to implement the CROSS JOIN you will have to rename the VehicleID, StartDateTime and EndDateTime on any of both tables. It is necessary for avoiding ambigous column names errors.

I rename the columns as follows:

VehicleID : LocationVehicleID and StatusVehicleID
StartDateTime : LocationStartDateTime and StatusStartDateTime
EndDateTime : LocationEndDateTime and StatusEndDateTime

After this you can use CROSSJOIN in the Total Days measure:

Total Days =
SUMX (
    FILTER (
        ADDCOLUMNS (
            FILTER (
                CROSSJOIN ( LocationEvents, VehicleStatusEvents ),
                LocationEvents[LocationVehicleID] = VehicleStatusEvents[StatusVehicleID]
                    && LocationEvents[LocationStartDateTime] <= VehicleStatusEvents[StatusEndDateTime]
                    && LocationEvents[LocationEndDateTime] >= VehicleStatusEvents[StatusStartDateTime]
            ),
            "CountOfDays", IF (
                [LocationStartDateTime] <= [StatusStartDateTime]
                    && [LocationEndDateTime] >= [StatusEndDateTime],
                DATEDIFF ( [StatusStartDateTime], [StatusEndDateTime], DAY ),
                IF (
                    [LocationStartDateTime] > [StatusStartDateTime]
                        && [LocationEndDateTime] >= [StatusEndDateTime],
                    DATEDIFF ( [LocationStartDateTime], [StatusEndDateTime], DAY ),
                    IF (
                        [LocationStartDateTime] <= [StatusStartDateTime]
                            && [LocationEndDateTime] <= [StatusEndDateTime],
                        DATEDIFF ( [StatusStartDateTime], [LocationEndDateTime], DAY ),
                        IF (
                            [LocationStartDateTime] >= [StatusStartDateTime]
                                && [LocationEndDateTime] <= [StatusEndDateTime],
                            DATEDIFF ( [LocationStartDateTime], [LocationEndDateTime], DAY ),
                            BLANK ()
                        )
                    )
                )
            )
        ),
        LocationEvents[LocationID] = [LocationID]
            && VehicleStatusEvents[ReasonCodeID] = [ReasonCodeID]
    ),
    [CountOfDays]
)

Then in Power BI you can build a matrix (or any other visualization) using this measure:

If you don't understand completely the measure expression, here is the T-SQL translation:

SELECT
    dt.VehicleID,
    dt.ReasonCodeID,
    dt.LocationID,
    SUM(dt.Diff) [Total Days]
FROM 
(
    SELECT
        CASE
            WHEN a.StartDateTime <= b.StartDateTime AND a.EndDateTime >= b.EndDateTime  -- Inside range
               THEN DATEDIFF(DAY, b.StartDateTime, b.EndDateTime)
            WHEN a.StartDateTime > b.StartDateTime AND a.EndDateTime >= b.EndDateTime  -- |-----|*****|....|
               THEN DATEDIFF(DAY, a.StartDateTime, b.EndDateTime)
            WHEN a.StartDateTime <= b.StartDateTime AND a.EndDateTime <= b.EndDateTime  -- |...|****|-----|
               THEN DATEDIFF(DAY, b.StartDateTime, a.EndDateTime)
            WHEN a.StartDateTime >= b.StartDateTime AND a.EndDateTime <= b.EndDateTime  -- |---|****|-----
               THEN DATEDIFF(DAY, a.StartDateTime, a.EndDateTime)
        END Diff,
        a.VehicleID,
        b.ReasonCodeID,
        a.LocationID --a.StartDateTime, a.EndDateTime, b.StartDateTime, b.EndDateTime
    FROM LocationEvents a
        CROSS JOIN VehicleStatusEvents b
    WHERE a.VehicleID = b.VehicleID
        AND 
        (
            (a.StartDateTime <= b.EndDateTime)
                AND (a.EndDateTime >= b.StartDateTime)
        )
) dt
GROUP BY dt.VehicleID,
         dt.ReasonCodeID,
         dt.LocationID

Note in T-SQL you could use an INNER JOIN operator too.

Let me know if this helps.

select      coalesce(l.VehicleID,s.VehicleID)   as VehicleID
           ,s.ReasonCodeID
           ,l.LocationID

           ,sum
            (
                datediff
                (
                    day
                   ,case when s.StartDateTime > l.StartDateTime then s.StartDateTime else l.StartDateTime end
                   ,case when s.EndDateTime   < l.EndDateTime   then s.EndDateTime   else l.EndDateTime   end
                )
            )   as TotalDays

from                    VehicleLocationEvents   as l

            full join   VehicleStatusEvents     as s

            on          s.VehicleID =
                        l.VehicleID

                    and case when s.StartDateTime > l.StartDateTime then s.StartDateTime else l.StartDateTime end   <=
                        case when s.EndDateTime   < l.EndDateTime   then s.EndDateTime   else l.EndDateTime   end   

group by    coalesce(l.VehicleID,s.VehicleID)
           ,s.ReasonCodeID
           ,l.LocationID

or

select      VehicleID
           ,ReasonCodeID
           ,LocationID
           ,sum (datediff (day,max_StartDateTime,min_EndDateTime))  as TotalDays

from       (select      coalesce(l.VehicleID,s.VehicleID)   as VehicleID
                       ,s.ReasonCodeID
                       ,l.LocationID

                       ,case when s.StartDateTime > l.StartDateTime then s.StartDateTime else l.StartDateTime end   as max_StartDateTime
                       ,case when s.EndDateTime   < l.EndDateTime   then s.EndDateTime   else l.EndDateTime   end   as min_EndDateTime

            from                    VehicleLocationEvents   as l

                        full join   VehicleStatusEvents     as s

                        on          s.VehicleID =
                                    l.VehicleID
            ) ls

where       max_StartDateTime <= min_EndDateTime

group by    VehicleID
           ,ReasonCodeID
           ,LocationID
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!