so I have a table called Value. I am trying to derive the Value for the last hour ( HR --> Timestamp(4) with TIME ZONE ) so that I can use it in a conditional statement in this Stored Procedure that I'm building. However, when i try the following, Oracle only returns a Date ( 01-Jan-19 ) rather than the previous hour ( 01-Jan-19 01.00.00.00000000 AM UTC ). What am I doing wrong?
select hr
, hr - (1/24) as Converted
from value;
If I try the following, I return ' 31-DEC-16 12.00.00.000000000 AM ' as the value for 'Converted' (no matter what the value for HR is):
select hr
, to_timestamp(hr - (1/24)) as converted
from value;
Which ultimately will be used as the definition of a variable in my stored procedure:
select max(value)
into v_Previous_hour
from value
where hr = hr - (1/24);
Am I missing something here? Thanks in advance.
Try this:
select hr
, cast( hr - (1/24) as timestamp) as Converted
from value;
Also, the query below is not going to do what you think it is.
select max(value)
into v_Previous_hour
from value
where hr = hr - (1/24);
Or you could use INTERVAL
:
SELECT TO_CHAR(HR) AS HR,
TO_CHAR(CAST(HR - INTERVAL '1' HOUR - INTERVAL '0.233' SECOND AS TIMESTAMP(4) WITH TIME ZONE)) AS HR_MINUS_ONE_HOUR
FROM VAL;
(Here I subtracted an additional 0.233 seconds just to make sure we were dealing with timestamps, per @AlexPoole's comment on @OldProgrammer's answer).
Oracle only returns a Date (01-Jan-19)
A date still has a time, your client just isn't showing it to you. You can use to_char()
to display it explicitly:
select to_char(hr - (1/24), 'YYYY-MM-DD HH24:MI:SS') from ...
It is a date because [that's the result of timestamp - number] arithmetic, and the timestamp is implicitly converted to a date before the subtraction. But you are losing both the fractional seconds and the time zone from your original value. Even if you cast back to a plain timestamp that information isn't recovered, and if you cast back to a timestamp with time zone it imolicitly picks up the current session's time zone, so won't necessarily match.
To keep both you can do what you suggested in your answer, or
select hr - interval '1' hour from ...
In your procedure, declare a variable of the same data type, eg (as an nonymous block):
declare
l_hr value.hr%type;
begin
select hr - interval '1' hour
into l_hr
from value
where ... ;
...
end;
Don't be tempted to store or manipulate the value as a string, keep it as its origial data type. It will be easieer to work with, safer and more efficient.
Have a look at this table Matrix of Datetime Arithmetic
When you perform {TIMESTAMP WITH TIME ZONE} - {NUMERIC}
then you get DATE
value, ie you loose the time zone information.
Better use INTERVAL, eg hr - INTERVAL '1' HOUR
or hr - NUMTODSINTERVAL(1, 'HOUR')
Anyway, I don't understand your question. If you ask " How to grab the previous hour of a timestamp(4) with TIMEZONE column? " then my answer would be
SELECT
EXTRACT(HOUR FROM hr - INTERVAL '1' HOUR) AS Solution_1
TO_CHAR(hr - INTERVAL '1' HOUR, 'HH24') AS Solution_2
FROM ...
Note, solution EXTRACT(HOUR FROM hr - INTERVAL '1' HOUR)
always returns the hour of UTC time, whereas TO_CHAR(hr - INTERVAL '1' HOUR, 'HH24')
returns hour from the stored time zone.
After 2 hours of hairpulling (and ironically after OldProgrammer was nice enough to provide me with an answer), I found a workaround:
select hr
, hr - numtodsinterval(1, 'hour') as converted
from value;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.