It seems like this should be possible with a single SQL statement using Oracle's analytic functions, perhaps with some combination of row_number(), lag(), and max() over. But I simply couldn't wrap my head around it. I kept on wanting to embed one analytic function within another, and I don't think you can do that. You can go in steps using Common Table Expressions, but I couldn't figure out how to make it work.
But a procedural solution is fairly straight forward using PL*SQL along with an extra table to store your result. I use row_number() to assign a chronological rank to each row in each of your source tables. You want a determinate result, so it's important to have a tie breaker in case you have duplicate date-times, hence my order by of dt, id. Here is a SQL-Fiddle demo.
Or look at the code below:
create table result (
dif number,
ida varchar(1),
idb varchar(1),
dta date,
dtb date
);
declare
prevA integer := 0;
prevB integer := 0;
begin
for rec in (
with
ordered_ta as (
select dt dta,
id ida,
row_number() over (order by dt, id) rowNumA
from ta
),
ordered_tb as (
select dt dtb,
id idb,
row_number() over (order by dt, id) rowNumB
from tb
)
select ta.*,
tb.*,
abs(dta - dtb) * 86400 dif
from ordered_ta ta
join ordered_tb tb
on dtb between (dta - 5/86400) and (dta + 5/86400)
order by rowNumA, rowNumB
)
loop
if rec.rowNumA > prevA and rec.rowNumB > prevB then
prevA := rec.rowNumA;
prevB := rec.rowNumB;
insert into result values (
rec.dif,
rec.ida,
rec.idb,
rec.dta,
rec.dtb
);
end if;
end loop;
end;
/
select * from result
union all
select null dif, id ida, null idb, dt dta, null dtb
from ta
where id not in (select ida from result)
union all
select null dif, null ida, id idb, null dta, dt dtb
from tb
where id not in (select idb from result)
;