ORACLE - SELECT with an aggregate function and MONTHS_BETWEEN - oracle

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)

Related

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>

Progressive LOOP Statement ORACLE

How to create a function that returns a float(ChargeTotal)?
ChargeTotal is based on a progressive table using number of batches.
num of batches | charge
----------------------------
1-10 | 0
11-20 | 50
21-30 | 60
31-40 | 70
40+ | 80
If number of batches is 25 then
num of batches | charge
----------------------------
1-10 | 0
11-20 | 50*10
21-30 | 60*5
----------------------------
total | 800 <number I need to be returned(ChargeTotal)
So far I have come up with the following, but I'm unsure how to get the total for each loop, or if it is even possible to do more than one FOR statements:
CREATE OR REPLACE FUNCTION ChargeTotal
RETURN FLOAT IS
total FLOAT;
BEGIN
FOR a in 1 .. 10 LOOP
FOR a in 11 .. 20 LOOP
FOR a in 21 .. 30 LOOP
FOR a in 40 .. 1000 LOOP
RETURN Total;
END ChargeTotal;
Ok so take into consideration that right now I have no DB available to test this (there might be some syntax errors etc).
But I am thinking something along this lines of code...
function ChargeTotal(xin number) return number is
cursor mycursor is
select lowLimit,highLimit,charge
from progressive_table order by lowLimit;
sum number;
segment number;
x number;
begin
sum:=0;
x :=xin;
for i in mycursor loop
segment := (i.highLimit-i.lowLimit)+1;
x := greatest ( x - segment,x);
sum := sum + segment*i.charge;
if (x<segment) then
return sum;
end if;
end loop;
return sum;
end;
I think you can do the calculation via single sql without complex function
the logic is:
you have weights for each "band"
calculate the "band" each row
count(*) over to calculate number of rows in each "band"
join your weight table to get sub.total for each band
use rollup to get grand total
sql
select r.num_of_batches
,sum(r.subtotal_charge)
from (
with weights as
(select 1 as num_of_batches, 0 as charge from dual
union all
select 2 as num_of_batches, 50 as charge from dual
union all
select 3 as num_of_batches, 60 as charge from dual
union all
select 4 as num_of_batches, 70 as charge from dual
union all
select 5 as num_of_batches, 80 as charge from dual
)
select distinct n.num_of_batches
, w.charge
, count(*) over (partition by n.num_of_batches) as cnt
, count(*) over (partition by n.num_of_batches) * charge as subtotal_charge
from (
select num, case when floor(num / 10) > 4 then 5 else floor(num / 10)+1 end as num_of_batches
from tst_brances b
) n
inner join weights w on n.num_of_batches = w.num_of_batches
order by num_of_batches
) r
group by ROLLUP(r.num_of_batches)
populate test data
create table tst_branches(num int);
declare
i int;
begin
delete from tst_brances;
for i in 1..10 loop
insert into tst_brances(num) values (i);
end loop;
for i in 11..20 loop
insert into tst_brances(num) values (i);
end loop;
for i in 21..25 loop
insert into tst_brances(num) values (i);
end loop;
for i in 31..32 loop
insert into tst_brances(num) values (i);
end loop;
for i in 41..43 loop
insert into tst_brances(num) values (i);
end loop;
for i in 51..55 loop
insert into tst_brances(num) values (i);
end loop;
commit;
end;
results
1 1 0
2 2 500
3 3 360
4 4 140
5 5 640
6 1640

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