There are 3 possible Datetime relational comparisons:
(1) PLSQL vs. PLSQL (2) SQL vs. SQL (3) SQL vs. PLSQL (or PLSQL vs. SQL)For each combination, run the Test Code and look the Output.
1. PLSQL Comparisons
Note 2017-03-26 [02:00 03:00) 'Europe/Zurich' is DST transit time.
--------------- Test Code ---------------
create or replace procedure test_comparison_plsql as
l_timestp_1 TIMESTAMP;
l_timestp_2 TIMESTAMP;
l_timestp_ltz_1 TIMESTAMP WITH LOCAL TIME ZONE;
l_timestp_ltz_2 TIMESTAMP WITH LOCAL TIME ZONE;
l_timestp_tz_1 TIMESTAMP WITH TIME ZONE;
l_timestp_tz_2 TIMESTAMP WITH TIME ZONE;
l_interval INTERVAL DAY TO SECOND;
l_str varchar2(40);
begin
l_interval := numtodsinterval(15, 'Minute');
l_timestp_1 := to_timestamp('2017-03-26 01:52:00', 'yyyy-mm-dd hh24:mi:ss');
l_timestp_2 := l_timestp_1 + l_interval;
dbms_output.put_line('l_timestp_1 = '||to_char(l_timestp_2,'DD*MON*YYYY HH24:MI:SS'));
dbms_output.put_line('l_timestp_2 = '||to_char(l_timestp_2,'DD*MON*YYYY HH24:MI:SS'));
l_timestp_ltz_1 := to_timestamp('2017-03-26 01:52:00', 'yyyy-mm-dd hh24:mi:ss');
l_timestp_ltz_2 := l_timestp_ltz_1 + l_interval;
dbms_output.put_line('l_timestp_ltz_1 = '||to_char(l_timestp_ltz_1,'DD*MON*YYYY HH24:MI:SS TZR TZD'));
dbms_output.put_line('l_timestp_ltz_2 = '||to_char(l_timestp_ltz_2,'DD*MON*YYYY HH24:MI:SS TZR TZD'));
l_timestp_tz_1 := to_timestamp_tz('2017-03-26 01:52:00 Europe/Zurich', 'yyyy-mm-dd hh24:mi:ss TZR TZD');
l_timestp_tz_2 := l_timestp_tz_1 + l_interval;
dbms_output.put_line('l_timestp_tz_1 = '||to_char(l_timestp_tz_1,'DD*MON*YYYY HH24:MI:SS TZR TZD'));
dbms_output.put_line('l_timestp_tz_2 = '||to_char(l_timestp_tz_2,'DD*MON*YYYY HH24:MI:SS TZR TZD'));
dbms_output.put_line('');
dbms_output.put_line('--------- CASE Comparisons ---------');
case
when l_timestp_1 < l_timestp_2 and FALSE then dbms_output.put_line('l_timestp_1 < l_timestp_2 WIN');
when l_timestp_ltz_1 < l_timestp_ltz_2 and FALSE then dbms_output.put_line('l_timestp_ltz_1 < l_timestp_ltz_2 WIN');
when l_timestp_tz_1 < l_timestp_tz_2 and FALSE then dbms_output.put_line('l_timestp_tz_1 < l_timestp_tz_2 WIN');
when l_timestp_1 < l_timestp_ltz_2 and FALSE then dbms_output.put_line('l_timestp_1 < l_timestp_ltz_2 WIN');
when l_timestp_1 < l_timestp_tz_2 and FALSE then dbms_output.put_line('l_timestp_1 < l_timestp_tz_2 WIN');
when l_timestp_ltz_1 < l_timestp_tz_2 and FALSE then dbms_output.put_line('l_timestp_ltz_1 < l_timestp_tz_2 WIN');
else dbms_output.put_line('CASE Comparisons OK');
end case;
dbms_output.put_line('');
dbms_output.put_line('--------- l_timestp_2 vs l_timestp_ltz_2 ---------');
l_str := 'l_timestp_2 < l_timestp_ltz_2 ';
begin
l_interval := l_timestp_2 - l_timestp_ltz_2; -- diff ORA-01878
dbms_output.put_line('l_timestp_2 - l_timestp_ltz_2 = '||l_interval);
if l_timestp_2 < l_timestp_ltz_2 then
dbms_output.put_line(l_str||'WIN');
else
dbms_output.put_line(l_str||'Lost');
end if;
exception when others then dbms_output.put_line(l_str||'*** '||SQLERRM);
end;
dbms_output.put_line('');
dbms_output.put_line('--------- l_timestp_ltz_2 vs l_timestp_tz_2 ---------');
l_str := 'l_timestp_ltz_2 < l_timestp_tz_2 ';
begin
l_interval := l_timestp_ltz_2 - l_timestp_tz_2; -- diff OK
dbms_output.put_line('l_timestp_ltz_2 - l_timestp_tz_2 = '||l_interval);
if l_timestp_ltz_2 < l_timestp_tz_2 then -- Comparison ORA-01878
dbms_output.put_line(l_str||'WIN');
else
dbms_output.put_line(l_str||'Lost');
end if;
exception when others then dbms_output.put_line(l_str||'*** '||SQLERRM);
end;
dbms_output.put_line('');
dbms_output.put_line('--------- l_timestp_tz_2 vs l_timestp_2 ---------');
l_str := 'l_timestp_tz_2 < l_timestp_2 ';
begin
l_interval := l_timestp_tz_2 - l_timestp_2; -- diff ORA-01878
dbms_output.put_line('l_timestp_tz_2 - l_timestp_2 = '||l_interval);
if l_timestp_tz_2 < l_timestp_2 then
dbms_output.put_line(l_str||'WIN');
else
dbms_output.put_line(l_str||'Lost');
end if;
exception when others then dbms_output.put_line(l_str||'*** '||SQLERRM);
end;
end;
/
alter session set time_zone = 'Europe/Zurich';
exec test_comparison_plsql;
--------------- Test Output ---------------
l_timestp_1 = 26*MAR*2017 02:07:00
l_timestp_2 = 26*MAR*2017 02:07:00
l_timestp_ltz_1 = 26*MAR*2017 01:52:00 EUROPE/ZURICH CET
l_timestp_ltz_2 = 26*MAR*2017 03:07:00 EUROPE/ZURICH CET
l_timestp_tz_1 = 26*MAR*2017 01:52:00 EUROPE/ZURICH CET
l_timestp_tz_2 = 26*MAR*2017 03:07:00 EUROPE/ZURICH CEST
--------- CASE Comparisons ---------
CASE Comparisons OK
--------- l_timestp_2 vs l_timestp_ltz_2 ---------
l_timestp_2 < l_timestp_ltz_2 *** ORA-01878: specified field not found in datetime or interval
--------- l_timestp_ltz_2 vs l_timestp_tz_2 ---------
l_timestp_ltz_2 - l_timestp_tz_2 = +00 00:00:00.000000
l_timestp_ltz_2 < l_timestp_tz_2 *** ORA-01878: specified field not found in datetime or interval
--------- l_timestp_tz_2 vs l_timestp_2 ---------
l_timestp_tz_2 < l_timestp_2 *** ORA-01878: specified field not found in datetime or interval
Look the above output, we can see:(1). For l_timestp_2 vs l_timestp_ltz_2, ORA-01878 appears when compute: l_interval := l_timestp_2 - l_timestp_ltz_2 because it is trying to convert l_timestp_2 to Time Zone "EUROPE/ZURICH". (2). For l_timestp_ltz_2 vs l_timestp_tz_2, compute: l_interval := l_timestp_ltz_2 - l_timestp_tz_2 is OK. But the Comparison: l_timestp_ltz_2 < l_timestp_tz_2 hits ORA-01878. If we look l_timestp_ltz_2: l_timestp_ltz_2 = 26*MAR*2017 03:07:00 EUROPE/ZURICH CET it is marked with wrong Time Zone Abbreviation "CET" because "26*MAR*2017 03:07:00 EUROPE/ZURICH" has to be with "CEST". As we know Time Zone Abbreviation "CET" is defined as TZ Offset "+01:00". Probably Oracle is trying to convert "26*MAR*2017 03:07:00 EUROPE/ZURICH" to TZ Offset "+01:00", it results in a non-exist datetime "26*MAR*2017 02:07:00 EUROPE/ZURICH", hence ORA-01878. However, it is not clear why Arithmetic: l_timestp_ltz_2 - l_timestp_tz_2 works. (3). For l_timestp_tz_2 vs l_timestp_2, same as Point (1).
2. SQL Comparisons
TODO: Comparisons of table column values in SQL Where Clause.
3. SQL and PLSQL Comparisons
TODO: Comparisons between table column values and bind variables in SQL Where Clause.