sum Data from column 1 where falls between range in column 2 - oracle

I'm fairly new to PL-SQL so could use a bit of help.
Table#1 contains:
LoanIntersestRates
------------------
4.5
4.0
3.5
3.0
2.5
Table #2 Contains:
ActualInterestRate LoanAmt
-----------------------------
4.6 356258.00
4.7 387958.25
2.6 485658.25
3.65 500562.00
4.1 434135.25
2.65 756254.02
4.5 286325.02
What I need to do is get a sum of the loanAmt where the ActualInterestRate is Exactly what is in table one.
Also, Need to sum up the loadAmts where the actualInterestrate is 1-50 points above each of the LoanInterestRates, 50-100 points above each of the LoanInterestRates and 100+ points above each of the LoanInterestRates.
Any help on this would be greatly appreciated. Thanks in advance!

Use the following query if you want to get the sum for rates mentioned in table 1
select lr.interest,sum(amount) from loaninterestrates lr, loaninterestamounts la
where lr.interest = la.interest
group by lr.interest
For step - 2 to find the sum for ranges use this
select la1.intrange,sum(la1.amount)from
(
select la.interest,la.amount,case when Remainder(la.interest*10,10) < 0 or Remainder(la.interest*10,10) = 5
then to_char(FLOOR(la.interest) + 0.5) || '-' || to_char(FLOOR(la.interest) + 1.0)
else to_char(FLOOR(la.interest)) || '-' || to_char(FLOOR(la.interest) + 0.5 )
end as intrange
from loaninterestamounts la
) la1
group by la1.intrange
sqlfiddle here: http://sqlfiddle.com/#!4/92f15/8

hi I have some misunderstanding your question but please check my sql
with t1 as
(select 4.5 as lir
from dual
union all
select 4.0
from dual
union all
select 3.5
from dual
union all
select 3.0
from dual
union all
select 2.5 from dual),
t2 as
(select 4.6 as air, 356258.00 as la
from dual
union all
select 4.7, 387958.25
from dual
union all
select 2.6, 485658.25
from dual
union all
select 3.65, 500562.00
from dual
union all
select 4.1, 434135.25
from dual
union all
select 2.65, 756254.02
from dual
union all
select 4.5, 286325.02 from dual),
t1_d as
(select lir as lir_low, lead(lir) over(order by lir) as lir_high from t1)
select t1_d.lir_low, sum(la) as sum_la
from t1_d, t2
where t2.air >= t1_d.lir_low
and ((t2.air < t1_d.lir_high) or (t1_d.lir_high is null))
group by t1_d.lir_low

Related

How to use the query builder of Symfony to make a date range counter and fill the gaps with zeros

I have a query that count the user by grouping them by sign up date.
return $this->createQueryBuilder('s')
->select(' date(s.created_at) as x, count(1) as y')
->where("s.created_at between datesub(now(), :months, 'Month') and now()")
->setParameter('months', $months)
->groupBy('x')
->orderBy('x')
->getQuery()
->getResult();
But their is currently gaps in my dataset.
So I have the sql request to fill the gaps, but I don't know how to create a complicated request with the Symfony's query builder.
SELECT ranger.ranger_date AS x, COALESCE(counter.counter_value, 0) as y
FROM (
SELECT DATE(s.created_at) AS counter_date, count(*) AS counter_value
FROM statistic AS s
WHERE s.created_at between DATE_SUB(NOW(), INTERVAL 3 MONTH) and now()
GROUP BY counter_date
) AS counter
RIGHT JOIN (
SELECT DATE(DATE_SUB(NOW(), INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY)) AS ranger_date
FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)units
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)tens
CROSS JOIN (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9)hundreds
WHERE DATE_SUB(NOW(), INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) BETWEEN DATE_SUB(NOW(), INTERVAL 3 MONTH) AND NOW()
) AS ranger
ON ranger.ranger_date = counter.counter_date
ORDER BY ranger.ranger_date
I have already tried with the createQuery method, but it did not work...
If your complex native sql query is successfully returning the result set you want:
You can simply prepare and execute the query as documented by Symfony.
If you need to hydrate entities then you can use the NativeQuery class.

How to breakdown data by month and showing zero for months with no data?

Using information in Table A, how can I produce results in Table B below?
Table A:
CASE_ID DATE_EFF COPAY STATUS
1 11/04/2016 10 A
1 11/20/2016 5 A
1 11/23/2016 5 R
1 12/01/2016 1 A
1 12/10/2016 2 A
1 12/12/2016 10 A
1 12/31/2016 50 R
For the above CASE_ID, we have dates in Nov 2016 and Dec 2016 only, however, I want to produce a breakdown of this CASE_ID for a period of 6 months as below where for each month the copays are summed where applicable as per the DATE_EFF and for the months that are not within the above dates, a zero is entered. Also, only records with copays with a status of 'A' are summed for any month -- so those with status of 'R' are ignored in the summation. For example, based on data in Table A above, the intended results are as follow:
Table B:
CASE_ID MONTH TOTAL_COPAY
1 01/2017 0
1 12/2016 13
1 11/2016 15
1 10/2016 0
1 09/2016 0
1 08/2016 0
I have below as a possible solution[using a with clause], but can this be achieved without the use of the 'with' clause?
Possible Solution:
WITH
XRF AS
( SELECT CASE_ID, COPAY, DATE_EFF
FROM Table_A WHERE STATUS = 'A'
)
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM XRF F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;
UPDATE AND SOLUTION:
Using the above query, I believe I am have answered my own question by implementing it as below -- not sure though if using this method is expensive when you have millions of records of such CASE_IDs. Any thoughts?
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM (SELECT CASE_ID, COPAY, DATE_EFF FROM TABLE_A WHERE STATUS = 'A') F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;

Subqueries in 2 tables

I have 2 tables: machine and work.
Table:machine
machine_no downtime location
A1-100-01 2 A1
A1-100 1.5 A1
A1-200 3 A1
CC3-100-01 0.5 CC3
CC3-100 1.5 CC3
Table:work
machine_no date
A1-100-01 2/4/14
A1-100 2/14/14
A1-200 2/6/14
CC3-100-01 3/15/14
CC3-100 3/2/14
I want the output to be like this:
machine_no total_downtime month
A1-100 3.5 (total of A1-100, A1-100-01) 02
A1-200 3 02
When location A1 is selected.
SELECT machine_no, SUM(downtime) as total_downtime
FROM (
SELECT
SUBSTR(machine_no, 1,
CASE WHEN INSTR(machine_no, '-', 1, 2) = 0
THEN LENGTH(machine_no)
ELSE INSTR(machine_no, '-', 1, 2)-1
END) as machine_no,
downtime
FROM machine
WHERE location='A1'
) InnerQuery
GROUP BY machine_no
How do I join table WORK and display the month? I'm using Oracle.
Thank you.
The month column's semantics in your expected query result is unclear. Assuming that it is another aggregation "key", then your query would be
select
regexp_substr(M.machine_no, '^[^-]+-[^-]+') as machine_no,
sum(downtime) as total_downtime,
to_char(W.date, 'mm') as month
from machine M
join work W
on W.machine_no = M.machine_no
group by
regexp_substr(M.machine_no, '^[^-]+-[^-]+'),
to_char(W.date, 'mm')
;
Assuming it is a (somehow) aggregated value, let's say via min() function, then your query would be
select
regexp_substr(M.machine_no, '^[^-]+-[^-]+') as machine_no,
sum(downtime) as total_downtime,
min(to_char(W.date, 'mm')) as month
from machine M
join work W
on W.machine_no = M.machine_no
group by
regexp_substr(M.machine_no, '^[^-]+-[^-]+')
;
Both of these, in addition, assume that the (total of A1-100, A1-100-01) in your expected result is just your note, not really a part of the result. But if not, then your query could be something along the lines of
select
regexp_substr(M.machine_no, '^[^-]+-[^-]+') as machine_no,
sum(downtime)||
case when count(1) > 1 then
' (total of '||
listagg(M.machine_no)
within group (order by M.machine_no)||
')'
end
as total_downtime,
to_char(W.date, 'mm') as month
from machine M
join work W
on W.machine_no = M.machine_no
group by
regexp_substr(M.machine_no, '^[^-]+-[^-]+'),
to_char(W.date, 'mm')
;
And even this works because of a few more assumptions about the (unsaid) properties of your machine and work tables, so I'm going to stop my answer here. :-)
User regular expression to take sub string of machine_no and to_char to get the month
WITH machine(machine_no, downtime, location) as (
select 'A1-100-01', 2, 'A1' from dual union all
select 'A1-100', 1.5, 'A1' from dual union all
select 'A1-200', 3, 'A1' from dual union all
select 'CC3-100-01', 0.5, 'CC3' from dual union all
select 'CC3-100', 1.5, 'CC3' from dual),
work(machine_no, ddate) as (
select 'A1-100-01', to_date('2/4/14', 'mm/dd/yyyy') from dual union all
select 'A1-100', to_date('2/14/14', 'mm/dd/yyyy') from dual union all
select 'A1-200', to_date('2/6/14', 'mm/dd/yyyy') from dual union all
select 'CC3-100-01', to_date('3/15/14', 'mm/dd/yyyy') from dual union all
select 'CC3-100', to_date('3/2/14', 'mm/dd/yyyy') from dual)
--End of data preparation
SELECT regexp_substr(m.machine_no, '^\w+-\w+') AS machine_no,
sum(m.downtime) downtime_sum,
to_char(w.ddate , 'MM') MONTH
FROM WORK w
JOIN machine m ON m.machine_no = w.machine_no
WHERE m.location = 'A1'
GROUP BY regexp_substr(m.machine_no, '^\w+-\w+'),
to_char(w.ddate , 'MM');
Output:
| MACHINE_NO | DOWNTIME_SUM | MONTH |
|------------|--------------|-------|
| A1-200 | 3 | 02 |
| A1-100 | 3.5 | 02 |

Oracle: elegant way to parse a number to 9,99 format

With Oracle 11g I want to parse a number to strip decimals if their value is 0 and keep two decimal figure after the decimal separator ',' if the value of decimals is different from 0
Example:
1,00 -> 1
1,001 -> 1
0,203 -> 0,20
And so on.
I've obtained something like that in a very unelegant way
select replace(trim(to_char (trunc ('0,2345',2),'9999999990.99')), '.', ',')
from dual
Do you know more elegant way? The output should be a char (not number).
Not sure it's much more elegant, but assuming your replace is to deal with different locales, this might work for you:
with t as (
select 1.00 as n from dual
union all select 1.001 from dual
union all select 0.203 from dual
union all select 0.2345 from dual
union all select 112.999 from dual
)
select n, regexp_replace(to_char(trunc(n, 2), '9999999990D00',
'NLS_NUMERIC_CHARACTERS='',.'''), '[,.]00$', null) as new_n
from t;
N NEW_N
---------- --------------
1 1
1.001 1
0.203 0,20
0.2345 0,23
112.999 112,99
The nls_param argument to to_char let's you dictate whether it used a comma or a period as the decimal separator. If you can set that at session level then the query looks a bit simpler. The regexp_replace strips ,00 (or .00, which come to think of it is overkill) from the end of th string.
As ThinkJet noted the regexp_replace is a bit excessive, and since the decimal seperator is defined in the column clase (and the format has no group separators anyway) it can be done with a plan replace:
with t as (
select 1.00 as n from dual
union all select 1.001 from dual
union all select 0.203 from dual
union all select 0.2345 from dual
union all select 112.999 from dual
union all select 13.08 from dual
)
select n, replace(trim(
to_char(trunc(n, 2), '9999999990D00', 'NLS_NUMERIC_CHARACTERS='',.''')),
',00', null) as new_n
from t;
N NEW_N
---------- --------------
1 1
1.001 1
0.203 0,20
0.2345 0,23
112.999 112,99
13.08 13,08
Still not sure this can be described as 'elegant' though.
To achieve correct results you must deal with numbers, not strings:
with t as (
select 1.00 as n from dual
union all select 1.001 from dual
union all select 0.203 from dual
union all select 0.2345 from dual
union all select 112.999 from dual
union all select 112.105 from dual
union all select 0 from dual
union all select -12.307 from dual
)
select
n,
decode( trunc(n,2) - trunc(n) ,
0, to_char(trunc(n), 'TM9', 'NLS_NUMERIC_CHARACTERS = '', '''),
to_char(trunc(n,2),'9999999990D00', 'NLS_NUMERIC_CHARACTERS = '', ''')
)
string_val
from t
SQLFiddle
P.S. Updated to get incorrect truncation instead of round, as in OP request.
Another variant
SELECT n,
to_char( trunc( n, 2 ),
case when mod( trunc( n, 2 ), 1 ) = 0
then '9990'
else '9990D00'
end, 'NLS_NUMERIC_CHARACTERS='',.''' ) val
from t
;
SQLFiddle demo

Oracle: transform wm_concat in an Analytic Function

I was reading that it should be really simple to use an Aggregate function as an Analytic Function link. I would like to use wm_concat in Oracle 10g as an analytic function.
It simply works as suggested!!! Really good thanks!
WITH temp as (
SELECT 'A' as master , 1 Col from dual
UNION SELECT 'A' , 3 from dual
UNION SELECT 'B' , 1 from dual
UNION SELECT 'B' , 2 from dual
UNION SELECT 'C' , 1 from dual)
SELECT
master,
wm_concat(Col) over (partition by master)
FROM
temp

Resources