Oracle WHERE Clause – Select Encompassing Rows

oraclewhere

I have a ROAD table that has a row for each vertex of each line:

+---------+--------------+-------------+
| ROAD_ID | VERTEX_INDEX | MEASURE_VAL |
+---------+--------------+-------------+
|       1 |            1 |           0 |
|       1 |            2 |         1.2 |
|       1 |            3 |         2.8 |
|       1 |            4 |         4.0 |
|       1 |            5 |         4.3 |
|       1 |            6 |         6.7 |
|       1 |            7 |         7.1 |
+---------+--------------+-------------+
|       2 |            1 |           0 |
|       2 |            2 |         5.2 |
|       2 |            3 |         7.7 |
|       2 |            4 |         9.6 |
|       2 |            5 |        11.8 |
+---------+--------------+-------------+
|       3 |            1 |           0 |
|       3 |            2 |         2.4 |
|       3 |            3 |         4.9 |
+---------+--------------+-------------+

And an EVENT table with rows that pertain to portions of roads:

+----------+---------+--------------+------------+
| EVENT_ID | ROAD_ID | FROM_MEASURE | TO_MEASURE |
+----------+---------+--------------+------------+
|       01 |       1 |          2.8 |        5.9 |
|       02 |       2 |          3.0 |        5.6 |
|       03 |       3 |            0 |        2.6 |
+----------+---------+--------------+------------+

I want to select the vertices from ROAD where the MEASURE_VAL encompasses/contains the EVENT table's FROM_MEASURE and TO_MEASURE (including the vertices in between):

+---------+--------------+-------------+
| ROAD_ID | VERTEX_INDEX | MEASURE_VAL |
+---------+--------------+-------------+
|       1 |            3 |         2.8 |
|       1 |            4 |         4.0 |
|       1 |            5 |         4.3 |
|       1 |            6 |         6.7 |
+---------+--------------+-------------+
|       2 |            1 |           0 |
|       2 |            2 |         5.2 |
|       2 |            3 |         7.7 |
+---------+--------------+-------------+
|       3 |            1 |           0 |
|       3 |            2 |         2.4 |
|       3 |            3 |         4.9 |
+---------+--------------+-------------+

In other words, I want to select vertices from ROADS where the MEASURE_VAL is between the event FROM_MEASURE and TO_MEASURE, and if the MEASURE_VAL does not exactly equal the FROM_MEASURE or TO_MEASURE, then also include the preceding and/or following vertices (where applicable).

Said yet differently again, I want to select the portion of the line that contains the event.

How can I do this?

Best Answer

You could just simply get the previous and next measure values with LAG and LEAD, and filter based on them:

select road_id, vertex_index, measure_val from (
  select
    r.road_id, r.vertex_index, r.measure_val, e.from_measure, e.to_measure,
    lag(r.measure_val, 1, r.measure_val) over 
      (partition by e.road_id order by r.vertex_index) as prev_measure_val,
    lead(r.measure_val, 1, r.measure_val) over 
      (partition by e.road_id order by r.vertex_index) as next_measure_val
  from
    road r join event e on (r.road_id = e.road_id)
) where prev_measure_val <= to_measure and next_measure_val >= from_measure;