Похоже, что вам нужно левое внешнее объединение, которое основано на отношении 'sub' и соответствующей дате / времени из двух таблиц:
select m.main_id,
v.val as orig_val,
vs.val as sub_val,
m.units,
v.hour,
v.date
from main m
join val_main_rel vmr on vmr.main_id = m.main_id
join val v on v.val_id = vmr.val_id
left join val_sub_main_rel vsmr on vsmr.main_id = m.main_id
left join val_sub vs on vs.val_sub_id = vsmr.val_sub_id
and vs.date_ = v.date
and vs.hour = v.hour;
Быстрая демонстрация с CTE для ваших примеров данныхс колонкой «date», переименованной в «date_», поэтому это действительный идентификатор:
-- CTEs for sample data, with 'date_' instead of 'date'
with main (main_id, main_name, created_dt, units) as (
select 1, 'Height', date '2018-12-14', 'INches' from dual
union all select 2, 'Weight', date '2018-12-12', 'LBs' from dual
),
val (val_id, val, hour, date_) as (
select 1, -87, '01:00 AM', date '2018-11-30' from dual
union all select 2, 8, '02:00 AM', date '2018-11-30' from dual
union all select 3, 18, '03:00 AM', date '2018-11-30' from dual
),
val_sub (val_sub_id, val, hour, date_) as (
select 1, 12, '01:00 AM', date '2018-11-30' from dual
),
val_main_rel (val_main_id, val_id, main_id) as (
select 1, 1, 2 from dual
union all select 2, 2, 2 from dual
union all select 3, 3, 1 from dual
),
val_sub_main_rel (val_sub_main_id, val_sub_id, main_id) as (
select 1, 1, 2 from dual
)
-- actual query
select m.main_id,
v.val as orig_val,
vs.val as sub_val,
m.units,
v.hour,
v.date_
from main m
join val_main_rel vmr on vmr.main_id = m.main_id
join val v on v.val_id = vmr.val_id
left join val_sub_main_rel vsmr on vsmr.main_id = m.main_id
left join val_sub vs on vs.val_sub_id = vsmr.val_sub_id
and vs.date_ = v.date_
and vs.hour = v.hour;
MAIN_ID ORIG_VAL SUB_VAL UNITS HOUR DATE_
---------- ---------- ---------- ------ -------- ----------
2 -87 12 LBs 01:00 AM 2018-11-30
2 8 LBs 02:00 AM 2018-11-30
1 18 INches 03:00 AM 2018-11-30
Множество внешних объединений и дублированных записей main_id
, которые есть в ваших фактических val_sub
таблицы сговорились сделать нежелательные совпадения, как вы описали в комментарии.Существует совпадение с таблицей отношений vsmr
, но не с таблицей vs
, если учитывать дату / час, но первого сопоставления с внешним соединением достаточно для создания дополнительных нежелательных строк в выводе.
С измененным CTE, имеющим второе вспомогательное значение:
-- CTEs for sample data, with 'date_' instead of 'date'
with main (main_id, main_name, created_dt, units) as (
select 1, 'Height', date '2018-12-14', 'INches' from dual
union all select 2, 'Weight', date '2018-12-12', 'LBs' from dual
),
val (val_id, val, hour, date_) as (
select 1, -87, '01:00 AM', date '2018-11-30' from dual
union all select 2, 8, '02:00 AM', date '2018-11-30' from dual
union all select 3, 18, '03:00 AM', date '2018-11-30' from dual
),
val_sub (val_sub_id, val, hour, date_) as (
select 1, 12, '01:00 AM', date '2018-11-30' from dual
-- extra row added below
union all select 2, 13, '02:00 AM', date '2018-11-30' from dual
),
val_main_rel (val_main_id, val_id, main_id) as (
select 1, 1, 2 from dual
union all select 2, 2, 2 from dual
union all select 3, 3, 1 from dual
),
val_sub_main_rel (val_sub_main_id, val_sub_id, main_id) as (
select 1, 1, 2 from dual
-- extra row added below
union all select 2, 2, 2 from dual
)
...
, исходный запрос получает:
MAIN_ID ORIG_VAL SUB_VAL UNITS HOUR DATE_
---------- ---------- ---------- ------ -------- ----------
2 -87 12 LBs 01:00 AM 2018-11-30
2 8 13 LBs 02:00 AM 2018-11-30
2 8 LBs 02:00 AM 2018-11-30
1 18 INches 03:00 AM 2018-11-30
2 -87 LBs 01:00 AM 2018-11-30
Так что я думаю, что вам нужно устранить их с помощью подзапроса,так что вместо этого вы можете сделать одно внешнее объединение:
select m.main_id,
v.val as orig_val,
vsx.val as sub_val,
m.units,
v.hour,
v.date_
from main m
join val_main_rel vmr on vmr.main_id = m.main_id
join val v on v.val_id = vmr.val_id
left join (
select vsmr.main_id, vs.val, vs.date_, vs.hour
from val_sub_main_rel vsmr
join val_sub vs on vs.val_sub_id = vsmr.val_sub_id
) vsx on vsx.main_id = m.main_id
and vsx.date_ = v.date_
and vsx.hour = v.hour;
, что дает более разумный результат:
MAIN_ID ORIG_VAL SUB_VAL UNITS HOUR DATE_
---------- ---------- ---------- ------ -------- ----------
2 -87 12 LBs 01:00 AM 2018-11-30
2 8 13 LBs 02:00 AM 2018-11-30
1 18 INches 03:00 AM 2018-11-30