Convert integer into percentage - oracle

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)

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

Extract hours from time

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>

ORACLE - SELECT with an aggregate function and MONTHS_BETWEEN

I have a difficulty with displaying the proper results. My formula is supposed to display those ENAME's of people who have Sum of SAL + COMM > 1200 and have worked at least 40 years. I think it's because of an NVL function inside. Can anyone tell me what is the problem?
SELECT ENAME
FROM SCOTT.EMP
WHERE NVL(SUM(SAL), 0) + NVL(SUM(COMM), 0) > 1200
AND MONTHS_BETWEEN(SYSDATE, HIREDATE) > 480
You don't need SUM (as a function):
where nvl(sal, 0) + nvl(comm, 0) > 1200
and hiredate < add_months(trunc(sysdate), -40 * 12)

calculate percentage of two select counts

I have a query like
select count(1) from table_a where state=1;
it gives 20
select count(1) from table_a where state in (1,2);
it gives 25
I would like to have a query to extract percentage 80% (will be 20*100/25).
Is possible to have these in only one query?
I think without testing that the following SQL command can do that
SELECT SUM(CASE WHEN STATE = 1 THEN 1 ELSE 0 END)
/SUM(CASE WHEN STATE IN (1,2) THEN 1 ELSE 0 END)
as PERCENTAGE
FROM TABLE_A
or the following
SELECT S1 / (S1 + S2) as S1_PERCENTAGE
FROM
(
SELECT SUM(CASE WHEN STATE = 1 THEN 1 ELSE 0 END) as S1
,SUM(CASE WHEN STATE = 2 THEN 1 ELSE 0 END) as S2
FROM TABLE_A
)
or the following
SELECT S1 / T as S1_PERCENTAGE
FROM
(
SELECT SUM(CASE WHEN STATE = 1 THEN 1 ELSE 0 END) as S1
,SUM(CASE WHEN STATE IN (1,2) THEN 1 ELSE 0 END) as T
FROM TABLE_A
)
you have the choice for performance or readability !
Just as a slight variation on #schlebe's first query, you can continue to use count() by making that conditional:
select count(case when state = 1 then state end)
/ count(case when state in (1, 2) then state end) as result
from table_a
or multiplying by 100 to get a percentage instead of a decimal:
select 100 * count(case when state = 1 then state end)
/ count(case when state in (1,2) then state end) as percentage
from table_a
Count ignores nulls, and both of the case expressions default to null if their conditions are not met (you could have else null to make it explicit too).
Quick demo with a CTE for dummy data:
with table_a(state) as (
select 1 from dual connect by level <= 20
union all select 2 from dual connect by level <= 5
union all select 3 from dual connect by level <= 42
)
select 100 * count(case when state = 1 then state end)
/ count(case when state in (1,2) then state end) as percentage
from table_a;
PERCENTAGE
----------
80
Why the plsql tag? Regardless, i think what you need is:
(select count(1) from table_a where state=1) * 100 / (select count(1) from table_a where state in (1,2)) from dual

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

Resources