Combine rows when the end time of one is the start time of another (Oracle)

前端 未结 5 479
旧时难觅i
旧时难觅i 2021-01-18 15:49

I just can\'t seem to get this query figured out. I need to combine rows of time-consecutive states into a single state.

This question is similar to the question fou

5条回答
  •  猫巷女王i
    2021-01-18 16:13

    Here's another approach:

    SELECT
        name,
        min(start_inst) AS start_inst,
        max(end_inst) AS end_inst,
        code,
        subcode
    FROM
        (
            SELECT
                A.*,
                COUNT
                (
                    CASE WHEN start_inst = previous_end_inst THEN NULL
                    ELSE 1
                    END
                )
                OVER
                (
                    ORDER BY
                        start_inst,
                        name,
                        code,
                        subcode
                ) AS group_number
            FROM
                (
                    SELECT
                        name,
                        start_inst,
                        end_inst,
                        LAG
                        (
                          end_inst
                        )
                        OVER
                        (
                            PARTITION BY
                                name,
                                code,
                                subcode
                            ORDER BY
                                start_inst
                        ) AS previous_end_inst,
                        code,
                        subcode
                    FROM
                        data
                ) A
            ) B
    GROUP BY
        name,
        code,
        subcode,
        group_number
    ORDER BY
        group_number
    

    Basically:

    1. For each row, subquery A finds the previous end time for the given name, code, and subcode.

    2. For each row, subquery B calculates the "group number" -- a running count of preceeding rows (in order of start_inst, name, code, and subcode) where the previous end time calculated in Step 1 is not equal to the start time.

    3. The outer query aggregates by group number.

    For better or worse, this approach, unlike @stevo's, will create a new "group" if there's a "gap" between the end time of one record and the start time of the next. For example, if you were to create a gap between 12:57 and 13:00 like this...

    UPDATE data
    SET start_inst = TO_DATE('9/12/2011 13:00', 'MM/DD/YYYY HH24:MI')
    WHERE start_inst = TO_DATE('9/12/2011 12:57', 'MM/DD/YYYY HH24:MI');
    

    ...the query above would return two rows like this...

    NAME                 START_INST       END_INST               CODE    SUBCODE
    -------------------- ---------------- ---------------- ---------- ----------
    .
    .
    .
    Person1              09/12/2011 12:26 09/12/2011 12:57        161         71
    Person1              09/12/2011 13:00 09/12/2011 13:07        161         71
    .
    .
    .
    

    ...whereas @stevo's query would return one row like this...

    NAME                 START_INST       END_INST               CODE    SUBCODE
    -------------------- ---------------- ---------------- ---------- ----------
    .
    .
    .
    Person1              12/09/2011 12:26 12/09/2011 13:07        161         71
    .
    .
    .
    

    Hope this helps.

提交回复
热议问题