Adding hours variable to date variable in Oracle - oracle

OK all-This may be simple but I can't see to find an answer via Google.
So I have a date value ('01/01/2020') and in another column I have a variable of hours (let's say 5) that needs to be added. SO I would have 01-JAN-20 05:00:00 in the end.
Any suggestions helpful. Thanks-
with t1 as (select TO_DATE('01/01/2020','DD/MM/YYYY') as DT, '5' as HR FROM DUAL)
select t1.* , ???? from t1;

You may simply add the correct fraction of a day, given the hour value:
WITH t1 AS (
SELECT TO_DATE('01/01/2020', 'DD/MM/YYYY') AS DT, '5' AS HR
FROM DUAL
),
t2 AS (
SELECT DT, DT + TO_NUMBER(HR) / 24 AS NEW_DT
FROM t1
)
SELECT
TO_CHAR(DT, 'DD-MM-YYYY HH24:MI:SS') AS DT,
TO_CHAR(NEW_DT, 'DD-MM-YYYY HH24:MI:SS') AS NEW_DT
FROM t2;
Demo

You can also use interval clause as follows:
with t1 as (select TO_DATE('01/01/2020','DD/MM/YYYY') as DT, '5' as HR FROM DUAL)
select t1.* ,
t1.dt + hr * interval '1' hour as new_dt -- this is solution
from t1;

Related

Sum totals of timestamp

I have the following query to calculate the summation timestamp
SELECT SUM(TIME_SPENT) FROM
(
select a - b as time_spent from tbl1 where name = 'xxx'
union all
select c - d as time_spent from tbl2 where name= 'yyy'
)a;
The sub-query return result as
+00 00:01:54.252000
But the entire query return error as ORA-00932: inconsistent datatypes: expected NUMBER got INTERVAL DAY TO SECOND.
Understand it required something like this
SELECT COALESCE (
(to_timestamp('2014-09-22 16:00:00','yyyy/mm/dd HH24:MI:SS') - to_timestamp('2014-09-22 09:00:00','yyyy/mm/dd HH24:MI:SS')) -
(to_timestamp('2014-09-22 16:00:00','yyyy/mm/dd HH24:MI:SS') - to_timestamp('2014-09-22 09:00:00','yyyy/mm/dd HH24:MI:SS')), INTERVAL '0' DAY) FROM DUAL;
How can achieve along with sub-queries that retrieve data from Timestamp type columns?
You cannot sum INTERVAL DAY TO SECOND in Oracle. I think this is one of the top rated open feature request.
You can cast the TIMESTAMP into DATE values, then the result is the difference in days. Multiply by 24*60*60 is you like to get seconds instead:
SELECT SUM(TIME_SPENT) * 24*60*60 FROM FROM
(
select CAST(a AS DATE) - CAST(b AS DATE) as time_spent from tbl1 where name = 'xxx'
union all
select CAST(d AS DATE) - CAST(d AS DATE) as time_spent from tbl2 where name= 'yyy'
);
Or you can write a function which converts INTERVAL DAY TO SECOND into seconds:
CREATE OR REPLACE FUNCTION GetSeconds(ds INTERVAL DAY TO SECOND) DETERMINISTIC RETURN NUMBER AS
BEGIN
RETURN EXTRACT(DAY FROM ds)*24*60*60
+ EXTRACT(HOUR FROM ds)*60*60
+ EXTRACT(MINUTE FROM ds)*60
+ EXTRACT(SECOND FROM ds);
END;
and use it like this:
SELECT SUM(TIME_SPENT), numtodsinterval(SUM(TIME_SPENT), 'second')
(
select GetSeconds(a-b) as time_spent from tbl1 where name = 'xxx'
union all
select GetSeconds(c-d) as time_spent from tbl2 where name= 'yyy'
);
try using below query
SELECT sum(extract(second from time_spent)) FROM
(
select a - b as time_spent from test2 where name = 'xxx'
union all
select c - d as time_spent from tbl2 where name= 'yyy'
)a;
Looks like time_spent column is timestamp type in your table an d it is not able to pass the correct data type in Sum function. Use extract function to get Seconds from time_spent.
with t(a,b) as (
select timestamp'2014-09-22 16:00:00.000', timestamp'2014-09-23 16:00:00.001' from dual union all
select timestamp'2014-09-22 16:00:00.000', timestamp'2014-09-24 16:00:00.001' from dual union all
select timestamp'2014-09-22 16:00:00.000', timestamp'2014-09-25 16:00:00.001' from dual union all
select timestamp'2014-09-22 16:00:00.000', timestamp'2014-09-26 16:00:00.001' from dual union all
select timestamp'2014-09-22 16:00:00.000', timestamp'2014-09-27 16:00:00.001' from dual
)
select
sum( (date'1-1-1'+(b-a)*24*60*60 - date'1-1-1')) as ssum_seconds_1,
round(sum( (date'1-1-1'+(b-a)*24*60*60 - date'1-1-1')), 3) as ssum_seconds_rounded,
numtodsinterval( round(sum( (date'1-1-1'+(b-a)*24*60*60 - date'1-1-1')), 3), 'second') dsint
from t
/

How to convert this code from oracle to redshift?

I am trying to implement the same in redshift and i am finding it little difficult to do that. Since redshift is in top of postgresql engine, if any one can do it in postgresql it would be really helpfull. Basically the code gets the count for previous two month at column level. If there is no count for exact previous month then it gives 0.
This is my code:
with abc(dateval,cnt) as(
select 201908, 100 from dual union
select 201907, 200 from dual union
select 201906, 300 from dual union
select 201904, 600 from dual)
select dateval, cnt,
last_value(cnt) over (order by dateval
range between interval '1' month preceding
and interval '1' month preceding ) m1,
last_value(cnt) over (order by dateval
range between interval '2' month preceding
and interval '2' month preceding ) m2
from (select to_date(dateval, 'yyyymm') dateval, cnt from abc)
I get error in over by clause. I tried to give cast('1 month' as interval) but still its failing. Can someone please help me with this windows function.
expected output:
Regards
This is how I would do it. In Redshift there's no easy way to generate sequences, do I select row_number() from an arbitrary table to create a sequence:
with abc(dateval,cnt) as(
select 201908, 100 union
select 201907, 200 union
select 201906, 300 union
select 201904, 600),
cal(date) as (
select
add_months(
'20190101'::date,
row_number() over () - 1
) as date
from <an arbitrary table to generate a sequence of rows> limit 10
),
with_lag as (
select
dateval,
cnt,
lag(cnt, 1) over (order by date) as m1,
lag(cnt, 2) over (order by date) as m2
from abc right join cal on to_date(dateval, 'YYYYMM') = date
)
select * from with_lag
where dateval is not null
order by dateval

calculate the running total over the column contain date difference in HH:MI:SS format in oracle

I have to find the running total over the column interval.
SELECT
( ( EXTRACT(DAY FROM intrvl) * 24 ) + ( EXTRACT(HOUR FROM intrvl) ) ) ||':'||
EXTRACT(MINUTE FROM intrvl) ||':'||
EXTRACT(SECOND FROM intrvl) ||':'|| as interval
FROM
(
SELECT
( to_timestamp(TO_CHAR(date_column_name,'dd-mon-rrrr hh:mi:ss') ) ) - ( to_timestamp(TO_CHAR(date_column_name,'dd-mon-rrrr hh:mi:ss') ) ) intrvl
FROM
dual
);
currrently Interval column of table has below data:
Interval(HH:mi:ss)
0:4:23
696:1:36
696:4:51
8760:1:18
The best I can come up with is this. Note that the interval data type does not take a format model for displaying - you can't force an interval of 25 hours to be displayed as 25:00:00 (although you can use that to INPUT an interval). Instead, it will be shown as 01 01:00:00 (meaning, a day and an hour).
with
tbl (interv) as (
select interval '0:4:23' hour(9) to second from dual union all
select interval '696:1:36' hour(9) to second from dual union all
select interval '696:4:51' hour(9) to second from dual union all
select interval '8760:1:18' hour(9) to second from dual
)
select interval '1' day * sum(date '2000-01-01' + interv - date'2000-01-01')
as sum_interv
from tbl;
SUM_INTERV
--------------------
+423 00:12:08.000000
In your original attempt you were trying to get a STRING output. I am not sure that's wise, but if that's what you need you can do it like so:
with
tbl (interv) as (
select interval '0:4:23' hour(9) to second from dual union all
select interval '696:1:36' hour(9) to second from dual union all
select interval '696:4:51' hour(9) to second from dual union all
select interval '8760:1:18' hour(9) to second from dual
)
, prep (sum_interv) as (
select interval '1' day * sum(date '2000-01-01' + interv - date'2000-01-01')
from tbl
)
select to_char( extract(day from sum_interv) * 24
+ extract(hour from sum_interv), 'fm999999999' ) || ':' ||
to_char( extract(minute from sum_interv), 'fm00' ) || ':' ||
to_char( extract(second from sum_interv), 'fm00' ) as sum_interv
from prep
;
SUM_INTERV
------------------
10152:12:08

Using Global Temporary Table in Subquery gives NULL

I am using following query.
SELECT SYSDATE,(SELECT P_PRICE_OPEN FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID='P8R3C2-R' AND P_DATE='22-OCT-18' AND P_VOLUME<>0 AND ROWNUM=1) FROM DUAL;
GTT_ADJ_PRICE_TABLE is global temporary table loaded with values when i have executed a function related to it. This GTT preserves rows after commit. This query gives me correct results.
But, If i run the query
SELECT WEEK_END, WEEK_START,
(SELECT P_PRICE_OPEN FROM GTT_ADJ_PRICE_TABLE WHERE P_DATE=WEEK_START) AS WEEKS_OPEN_PRICE,
(SELECT MAX(P_PRICE_HIGH) FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID=FID AND P_DATE<=WEEK_END
AND P_DATE>=WEEK_START AND P_VOLUME<>0) AS WEEKLY_HIGH,
(SELECT MIN(P_PRICE_LOW) FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID=FID AND P_DATE<=WEEK_END
AND P_DATE>=WEEK_START AND P_VOLUME<>0) AS WEEKLY_LOW,
(SELECT SUM(P_VOLUME) FROM GTT_ADJ_PRICE_TABLE WHERE FSYM_ID=FID AND P_DATE<=WEEK_END
AND P_DATE>=WEEK_START AND P_VOLUME<>0) AS WEEKLY_VOLUME,
P_PRICE
FROM (
SELECT ROWNUM,FID,WEEK_END,P_VOLUME,P_PRICE,
(SELECT P_DATE FROM FP_V2_FP_BASIC_PRICES WHERE FSYM_ID=FID AND P_DATE>=TRUNC(WEEK_END, 'IW') AND P_VOLUME<>0 AND ROWNUM=1) AS WEEK_START
FROM (
SELECT
ROWNUM,FSYM_ID AS FID, WEEK_END,P_VOLUME, P_PRICE,P_PRICE_OPEN,P_PRICE_HIGH,P_PRICE_LOW
FROM (
SELECT ROWNUM,FSYM_ID,P_DATE AS WEEK_END, P_PRICE,P_VOLUME, P_PRICE_OPEN,P_PRICE_HIGH,P_PRICE_LOW,
CASE
WHEN (TO_CHAR(P_DATE,'D') >= AVG(TO_CHAR(P_DATE,'D')) OVER (order by P_DATE DESC rows between 1 preceding and current row) and ROWNUM>=1) or TO_CHAR(P_DATE,'D')=6
THEN 1
ELSE 0
END AS WEEKFLAG
FROM(
SELECT * FROM TABLE (ADJUSTED_PRICE('P8R3C2-R')) WHERE P_VOLUME<>0
)
)WHERE WEEKFLAG=1
)
);
It gives me NULL in WEEKS_OPEN_PRICE,WEEKLY_HIGH,WEEKLY_LOW,WEEKLY_VOLUME.
Please help me to resolve the issue. Thanks in anticipation.
Try with WITH clause. I hope a below query works. I don't have possibility to check.
WITH adjustedPrice AS (
SELECT *
FROM TABLE(adjusted_price('P8R3C2-R'))
WHERE p_volume <> 0
AND TO_CHAR(p_date, 'DY') NOT IN ('SAT', 'SUN')
)
SELECT ap.week,
ap.week_start,
ap.week_end,
ap.weeks_high_price,
ap.weeks_low_price,
ap.weekly_volume,
ws.p_price_open AS weeks_open_price,
we.p_price AS weeks_close_price
FROM (
SELECT TRUNC(p_date, 'IW') AS week,
TRUNC(MIN(p_date)) AS week_start,
TRUNC(MAX(p_date)) AS week_end,
MAX(p_price_high) AS weeks_high_price,
MIN(p_price_low) AS weeks_low_price,
SUM(p_volume) AS weekly_volume
FROM adjustedPrice
GROUP BY TRUNC(p_date, 'IW')
) ap
INNER JOIN adjustedPrice ws ON ws.p_date = ap.week_start
INNER JOIN adjustedPrice we ON we.p_date = ap.week_end
ORDER BY week DESC;
Wanted to post as a comment. But it wont fit there thats why writing it as an answer.
I tried this code to get the week start, end , weeks high price, weeks low price, weekly volume.
select
trunc("P_DATE", 'IW') as week,
min(trunc("P_DATE")) as week_start,
max(trunc("P_DATE")) as week_end,
MAX(P_PRICE_HIGH) AS WEEKS_HIGH_PRICE,
MIN(P_PRICE_LOW) AS WEEKS_LOW_PRICE,
SUM(P_VOLUME) AS WEEKLY_VOLUME
from TABLE
(ADJUSTED_PRICE('P8R3C2-R'))
WHERE
P_VOLUME<>0 AND to_char("P_DATE", 'DY') not in ('SAT','SUN')
group by
trunc("P_DATE", 'IW')
ORDER BY
trunc("P_DATE", 'IW') DESC;
That gave me results in hardly 2-4 seconds. But i want to get the weeks open price where date will be equal to WEEK_START and weeks closing price where date will be equal to WEEK_END.
I tried following approach for the same. But its taking too much time (like 300+ seconds).
SELECT
WEEK,WEEK_START, WEEK_END, WEEKS_HIGH_PRICE,WEEKS_LOW_PRICE,WEEKLY_VOLUME,
(SELECT P_PRICE_OPEN FROM TABLE (ADJUSTED_PRICE('P8R3C2-R')) WHERE P_VOLUME<>0 AND P_DATE=WEEK_START) AS WEEKS_OPEN_PRICE,
(SELECT P_PRICE FROM TABLE (ADJUSTED_PRICE('P8R3C2-R')) WHERE P_VOLUME<>0 AND P_DATE=WEEK_END) AS WEEKS_CLOSE_PRICE
FROM
(
select
trunc("P_DATE", 'IW') as week,
min(trunc("P_DATE")) as week_start,
max(trunc("P_DATE")) as week_end,
MAX(P_PRICE_HIGH) AS WEEKS_HIGH_PRICE,
MIN(P_PRICE_LOW) AS WEEKS_LOW_PRICE,
SUM(P_VOLUME) AS WEEKLY_VOLUME
from TABLE
(ADJUSTED_PRICE('P8R3C2-R'))
WHERE
P_VOLUME<>0 AND to_char("P_DATE", 'DY') not in ('SAT','SUN')
group by
trunc("P_DATE", 'IW')
ORDER BY
trunc("P_DATE", 'IW') DESC
);
If anybody can help me to improve the output time is most welcome.

How to query for a specific day of the month in Oracle

Trying to automate a query that will pull data for the current month where the day of the month (in the date field) is >= the 15th. Is this possible? If so, what is the syntax to achieve this?
I want to be able to run this query each month without having to change anything. So in May, it would automatically pull any item where the date was >= 5/15/16. In June, it would pull items where the date was >= 6/15/16. And so on.....
Any help in this would be greatly appreciated. Thanks
This will allow you to use any indexes you have on your date_field column:
SELECT *
FROM table_name
WHERE date_field >= TRUNC( SYSDATE, 'MM' ) + INTERVAL '14' DAY
AND date_field < ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), 1 );
If your date/time fields are of type timestamp you can do
select x from <your_table>
where EXTRACT(DAY from <timestamp field>) >=15
and EXTRACT(MONTH from <timestamp field>) = EXTRACT(MONTH FROM CURRENT_TIMESTAMP)
and EXTRACT(YEAR from <timestamp field>) = EXTRACT(YEAR FROM CURRENT_TIMESTAMP);
I think what you're after is something like:
with sample_data as (select 1 id, to_date('01/06/2016', 'dd/mm/yyyy') dt from dual union all
select 2 id, to_date('10/06/2016', 'dd/mm/yyyy') dt from dual union all
select 3 id, to_date('14/06/2016', 'dd/mm/yyyy') dt from dual union all
select 4 id, to_date('15/06/2016', 'dd/mm/yyyy') dt from dual union all
select 5 id, to_date('16/06/2016', 'dd/mm/yyyy') dt from dual union all
select 6 id, to_date('30/06/2016', 'dd/mm/yyyy') dt from dual union all
select 7 id, to_date('01/07/2016', 'dd/mm/yyyy') dt from dual)
select *
from sample_data
where dt >= trunc(sysdate, 'mm') + 14
and dt < last_day(trunc(sysdate)) + 1;
ID DT
---------- ----------
4 15/06/2016
5 16/06/2016
6 30/06/2016
(If you wanted rows with any date greater than the 15th of the current month, then remove the last predicate in the where clause.)

Resources