Extract hours from time - oracle

I am try to find solution but I couldn't. The problem is following.
1 ) I want to extract hours from time and add minutes converted to hours
(SUM(SUBSTRING_INDEX(aa.Quantity, ':', 1)) + TRUNCATE((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) / 60),0))
So for example If I have 16hours:35minutes. I want to display 16 and minutes part should be added to hours as 16,5 hours for example
2) extract minutes from time and find reminder (modulo)
LPAD((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) % 60), 2, 0)
I found this part of solution but this soulution is wrote in MySQL and I need Oracle SQL solution
CONCAT(
-- extract hours froAm time and add minutes converted to hours
(SUM(SUBSTRING_INDEX(aa.Quantity, ':', 1)) + TRUNCATE((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) / 60),0))
, ':',
-- extract minutes from time and find reminder (modulo)*/
LPAD((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) % 60), 2, 0)
) AS W_TOTAL_SUM
Also I try to convert this MySQL statment to Oracle SQL by using following site, but unfortunettly I didn't get correct result since it returns same output as input
http://www.sqlines.com/online
So exactly same as I decribe but only in Oracle SQL. I would be very thankfull since I try to fix this problem a couple of hours and couldn't find any solution for this problem
Here is my solution which doesn't work. I get error
ORA-00907: missing right parenthesis
SELECT
(SUM(SUBSTR(A.Quantity, ':', 1)) + TRUNC((SUM(SUBSTR(A.Quantity, ':', -1)) / 60),0)), ':' ,
MOD(LPAD(SUM(SUBSTR(A.Quantity, ':', -1)), 60),2,0)
-- MOD(LPAD((SUM(SUBSTRING_INDEX(A.Quantity, ':', -1)) % 60), 2, 0)
-- LPAD((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) % 60), 2, 0)
AS TOTAL_SUM FROM (
SELECT
ata.ATAID AS AtaId, ata.ProjectID, ata.StartDate, ataAW.Quantity
FROM
ata
INNER JOIN
weekly_report
ON
weekly_report.ataId = ata.ATAID
INNER JOIN
ata_articles ataAW
ON
ataAW.wrId = weekly_report.id
WHERE
ata.ATAID = 10987
AND
ataAW.type = 1
OR
ataAW.type = 2
OR
ataAW.type = 3
AND
(weekly_report.status != 3 AND weekly_report.status != 4)
AND
(
weekly_report.year < (SELECT year FROM weekly_report WHERE id = 89)
OR
(
weekly_report.year <= (SELECT year FROM weekly_report WHERE id = 89)
AND
weekly_report.week <= (SELECT week FROM weekly_report WHERE id = 89)
)
)
) A
group by A.AtaId
order by A.AtaId ASC
The common problem is
LPAD((SUM(SUBSTR(A.Quantity, ':', -1)) MOD 60), 2, 0)
Here is output which I expect
TOTAL_SUM
101:24

This is how I understood the question:
sample data in lines #1 - 2
extract hours (line #3)
extract minutes (line #5), divide it by 60 (as number of minutes in an hour)
hours + minutes = result
SQL> with test (col) as
2 (select '16hours:35minutes' from dual)
3 select to_number(regexp_substr(col, '\d+', 1, 1)) -- hours
4 +
5 round(to_number(regexp_substr(col, '\d+', 1, 2)) / 60, 2) -- minutes
6 as result
7 from test
8 /
RESULT
----------
16,58
SQL>

Related

pl sql payment calculation

I need help with PVA calculation in PL/SQL .I have formula:
Annuity = r * PVA Ordinary / [1 – (1 + r)-n]
Where:
PVA Ordinary = Present value of an ordinary annuity
r = Effective interest rate
n = Number of periods.
enter image description here
You can use:
DECLARE
principal NUMBER := 9000;
r NUMBER := 0.015;
n NUMBER := 5;
start_dt DATE := DATE '2022-07-14';
payment NUMBER := r * principal / (1 - POWER(1 + r, -n));
amt NUMBER := principal;
interest NUMBER;
pmt_dt DATE;
BEGIN
FOR i IN 1 .. n LOOP
pmt_dt := ADD_MONTHS(start_dt, i);
pmt_dt := pmt_dt + CASE pmt_dt - TRUNC(pmt_dt, 'IW')
WHEN 5 THEN 2 -- Saturday
WHEN 6 THEN 1 -- Sunday
ELSE 0 -- Weekday
END;
interest := amt * r;
amt := amt - payment + interest;
DBMS_OUTPUT.PUT_LINE(
TO_CHAR(i, 'fm0')
|| ', ' || TO_CHAR(pmt_dt, 'YYYY-MM-DD (DY)')
|| ', ' || TO_CHAR(payment, '9990.00')
|| ', ' || TO_CHAR(interest, '990.00')
|| ', ' || TO_CHAR(payment - interest, '9990.00')
|| ', ' || TO_CHAR(amt, '9990.00')
);
END LOOP;
END;
/
Which outputs:
1, 2022-08-15 (MON), 1881.80, 135.00, 1746.80, 7253.20
2, 2022-09-14 (WED), 1881.80, 108.80, 1773.01, 5480.19
3, 2022-10-14 (FRI), 1881.80, 82.20, 1799.60, 3680.59
4, 2022-11-14 (MON), 1881.80, 55.21, 1826.60, 1853.99
5, 2022-12-14 (WED), 1881.80, 27.81, 1853.99, -0.00
Or, in SQL using a MODEL clause:
WITH data (id, start_date, principal, rate, period ) AS (
SELECT 1, DATE '2022-07-14', 9000, 0.015, 5 FROM DUAL
)
SELECT pmt_dt + CASE pmt_dt - TRUNC(pmt_dt, 'IW')
WHEN 5 THEN 2
WHEN 6 THEN 1
ELSE 0
END AS pmt_dt,
ROUND(payment, 2) AS payment,
ROUND(interest, 2) AS interest,
ROUND(payment - interest, 2) AS reduction,
ROUND(balance, 2) AS balance
FROM data
MODEL
PARTITION BY (id)
DIMENSION BY (1 AS key)
MEASURES (
start_date,
principal,
rate,
period,
DATE '1900-01-01' AS pmt_dt,
rate * principal / (1 - POWER(1 + rate, -period)) AS payment,
0 AS interest,
0 AS balance
)
RULES SEQUENTIAL ORDER ITERATE (100) UNTIL (balance[ITERATION_NUMBER+1] <= 0) (
payment[ITERATION_NUMBER+1] = payment[1],
pmt_dt[ITERATION_NUMBER+1] = ADD_MONTHS(start_date[1], ITERATION_NUMBER+1),
interest[ITERATION_NUMBER + 1]
= COALESCE(balance[ITERATION_NUMBER],principal[1]) * rate[1],
balance[ITERATION_NUMBER+1]
= COALESCE(balance[ITERATION_NUMBER],principal[1])
- payment[1] + interest[ITERATION_NUMBER+1]
)
ORDER BY id, key
Which outputs:
PMT_DT
PAYMENT
INTEREST
REDUCTION
BALANCE
15-AUG-22
1881.8
135
1746.8
7253.2
14-SEP-22
1881.8
108.8
1773.01
5480.19
14-OCT-22
1881.8
82.2
1799.6
3680.59
14-NOV-22
1881.8
55.21
1826.6
1853.99
14-DEC-22
1881.8
27.81
1853.99
0
db<>fiddle here

Case when Between Dates

I am trying to flag data on a rolling Date selected and prior 4 months criteria.
How do I write a case when that says
Case when X=1 and Y=2 And between Date- 4months Then '1'
When X =2 and Date(Year/month)- 4monthsDate Then '2'
END ) AS Flag
GROUP BY MONTHOFDATE
Your best bet it to use the ADD_MONTHS function:
CASE
WHEN X = 1 AND
Y = 2 AND
SOME_DATE BETWEEN ADD_MONTHS(SYSDATE, -4) AND SYSDATE
THEN '1'
WHEN X = 2 AND
SOME_DATE BETWEEN ADD_MONTHS(SYSDATE, -4) AND SYSDATE
THEN '2'
END AS FLAG
Best of luck.

Oracle performance tuning order by is taking time

Am having query,in which two fields and getting as output pps_id and total_weight. Here pps_id is the column from the table and total_weight we are calculating from inner query. after doing all process in query we are order by the query by total weight. Its taking more cost and response.Is there any way to improve this query performance.
SELECT PPS_ID, TOTAL_WEIGHT
FROM ( SELECT PPS_ID, TOTAL_WEIGHT
FROM (SELECT pps_id,
ROUND (
( ( (60 * name_pct_match / 100)
+ prs_weight
+ year_weight
+ dt_weight)
/ 90)
* 100)
total_weight
FROM (SELECT pps_id,
ROUND (func_compare_name ('aaaa',
UPPER (name_en),
' ',
60))
name_pct_match,
DECODE (prs_nationality_id, 99, 15, 0)
prs_weight,
10 mother_weight,
100 total_attrib_weight,
CASE
WHEN TO_NUMBER (
TO_CHAR (birth_date, 'yyyy')) =
1986
THEN
5
ELSE
0
END
year_weight,
CASE
WHEN TO_CHAR (
TO_DATE ('12-JAN-86',
'DD-MON-RRRR'),
'dd') =
TO_CHAR (birth_date, 'dd')
AND TO_CHAR (
TO_DATE ('12-JAN-86',
'DD-MON-RRRR'),
'mm') =
TO_CHAR (birth_date, 'mm')
THEN
10
WHEN TO_DATE ('12-JAN-86', 'DD-MON-RRRR') BETWEEN birth_date
- 6
AND birth_date
+ 6
THEN
8
WHEN TO_DATE ('12-JAN-86', 'DD-MON-RRRR') BETWEEN birth_date
- 28
AND birth_date
+ 28
THEN
5
WHEN TO_DATE ('12-JAN-86', 'DD-MON-RRRR') BETWEEN birth_date
- 90
AND birth_date
+ 90
THEN
3
ELSE
0
END
dt_weight
FROM individual_profile
WHERE birth_date = '12-JAN-86'
AND IS_ACTIVE = 1
AND gender_id = 1
AND ROUND (func_compare_name ('aaa',
UPPER (name_en),
' ',
60)) > 20))
WHERE TOTAL_WEIGHT >= 100
ORDER BY total_weight DESC)
WHERE ROWNUM <= 10
i have tried by splitting the query and put values in temp tables and tried but it also taking time. I want to improve the performance of the query

Convert integer into percentage

I don't know how to convert integer into percentage, please help me. Thank you
Here's the query:
SELECT 'Data' || ',' ||
TO_CHAR(D.DTIME_DAY,'MM/dd/yyyy') || ',' ||
NVL(o.CNT_OPENED,0) || ',' || --as cnt_opened
NVL(c.CNT_CLOSED,0) --as cnt_closed
FROM OWNER_DWH.DC_DATE d
LEFT JOIN (SELECT TRUNC(t.CREATE_TIME, 'MM') AS report_date,
count(*) AS cnt_opened
FROM APP_ACCOUNT.OTRS_TICKET t
WHERE t.CREATE_TIME BETWEEN SYSDATE -120 AND SYSDATE
GROUP BY TRUNC(t.CREATE_TIME, 'MM')) o
ON d.DTIME_DAY=o.REPORT_DATE
LEFT JOIN (SELECT TRUNC(t.CLOSE_TIME, 'MM') as report_date,
count(*) AS cnt_closed
FROM APP_ACCOUNT.OTRS_TICKET t
WHERE t.CLOSE_TIME BETWEEN SYSDATE -120 AND SYSDATE
GROUP BY TRUNC(t.CLOSE_TIME, 'MM')) c
ON D.DTIME_DAY=c.REPORT_DATE
WHERE d.DTIME_DAY BETWEEN SYSDATE -120 AND TRUNC(SYSDATE) -1 AND
d.DTIME_DAY = TRUNC(d.DTIME_DAY, 'MM') AND
TRUNC(d.DTIME_DAY,'MM')= d.DTIME_DAY
ORDER BY D.DTIME_DAY;
The output of that query:
Data,10/01/2013,219,201
Data,11/01/2013,249,234
Data,12/01/2013,228,224
Data,01/01/2014,269,256
example output that I need is like this:
Data,10/01/2013,219, 52%, 201, 45%
Data,11/01/2013,249, 75%, 234, 60%
.......
........
Formula:
create_time + close time = total / create_time (for cnt_opened each column) = percentage
create_time + close time = total / close_time (for cnt_closed each column) = percentage
Try this:
Basically just add the total of CNT_OPENED and CNT_CLOSED, then whichever you want to take the percentage of, multiply that by 100 and divide by the sum.
For instance, CNT_OPENED = 219 and CNT_CLOSED = 201 so the total is 420. Multiply CNT_OPENED by 100 and then divide by 420 -> (219 * 100) / 420 = 52. Do the same thing with CNT_CLOSED.
Note that this WILL result in an exception if both CNT_OPENED and CNT_CLOSED are 0.
SELECT 'Data'
||','||TO_CHAR(D.DTIME_DAY,'MM/dd/yyyy')
||','||NVL(o.CNT_OPENED,0) --as cnt_opened
||','||(NVL(o.CNT_OPENED,0) * 100) / (NVL(o.CNT_OPENED,0) + NVL(o.CNT_CLOSED,0)) || '%'
||','||NVL(c.CNT_CLOSED,0) --as cnt_closed
||','||(NVL(o.CNT_CLOSED,0) * 100) / (NVL(o.CNT_OPENED,0) + NVL(o.CNT_CLOSED,0)) || '%'
That will also potentially give you a million decimal places, so if you only want to take it out to a couple, simply use the TRUNC function and specify your precision (2 decimal places in this case):
TRUNC((NVL(o.CNT_OPENED,0) * 100) / (NVL(o.CNT_OPENED,0) + NVL(o.CNT_CLOSED,0)), 2)

Error while converting date string to date

In my project in my_table time of any event is stored in number format. Now I have to convert it to oracle datetime format.
Here is an explanation below:
Example1 :
•Sched_Arr_Tm = 0450, will equal 04:30 am (the first 2 is HH (24 hour clock. Since 04 < 12, then just use that number as the hour)) and the next 2 are the fractional equivalent of an hour (.50 * 60 min = 30 min)
•Sched_Arr_Tm = 2100, will equal 9:00 PM (since 21> 12, then take 21-12=9)
•Sched_Arr_Tm = 1475, will equal 02:45 Pm (the first 2 is HH (24 hour clock. Since 14 > 12. Then take 14-12=2), then just use that number as the hour)) and the next 2 are the fractional equivalent of an hour (.75 * 60 min = 45 min)
•Sched_Arr_Tm = 0075, will equal 12:45 AM (since the hour = 00, then the hour= 12) and the next 2 are the fractional equivalent of an hour (.75 * 60 min = 45 min)
I am able to extract data according to above login but getting error while converting it to date.
select sched_arr_tm,
LPAD(substr(tn.sched_arr_tm, 1,length(tn.sched_arr_tm) - 2),2,'0') as HH,
RPAD(TRUNC(TO_NUMBER(substr(tn.sched_arr_tm,3,length(tn.sched_arr_tm) - 2)) * .60,0),2,'0') as MM,
'00' AS SS,
LPAD(substr(tn.sched_arr_tm,1,length(tn.sched_arr_tm) - 2),2,'0')
||':' ||
RPAD(TRUNC(TO_NUMBER(substr(tn.sched_arr_tm,3,length(tn.sched_arr_tm) - 2)) * .60,0),2,'0')
||':'||
LPAD(0,2,0) AS DTTM,
TO_DATE(LPAD(substr(tn.sched_arr_tm,1,length(tn.sched_arr_tm) - 2),2,'0')
||':' ||
RPAD(TRUNC(TO_NUMBER(substr(tn.sched_arr_tm,3,length(tn.sched_arr_tm) - 2)) * .60,0),2,'0')
||':'||
LPAD(00,2,0),'HH24:MI:SS') AS DTTM,
tn.sched_slip_arr_tm
from MY_TABLE;
I am getting this error:
ORA-01858: a non-numeric character was found where a numeric was expected.
you can do this with:
SQL> with data as (select 450 Sched_Arr_Tm from dual
2 union all
3 select 1475 from dual
4 union all
5 select 2100 from dual)
6 select Sched_Arr_Tm, to_date(hours||':'||(60*(mins/100)), 'hh24:mi')
7 from (select Sched_Arr_Tm, substr(Sched_Arr_Tm, -2) mins,
8 substr(Sched_Arr_Tm, 1, length(Sched_Arr_Tm)-2) hours
9 from data)
10 /
SCHED_ARR_TM TO_DATE(HOURS||':
------------ -----------------
450 01-jan-2013 04:30
1475 01-jan-2013 14:45
2100 01-jan-2013 21:00
SQL>

Resources