Oracle SQL query to do Interpolation In Oracle 12c - oracle

Interpolated results
Dear Experts,
I have interpolated values for AddOn correctly ( highlighted in yellow) using the analytic functions regr_slope and regr_intercept with the script below
with CLP_ADDON_CALC_STG (addon_product, term_years, underlying_term_years, addon) as
( SELECT 'CCREPO', 0.5, 5 , 0.0447 FROM DUAL UNION ALL
SELECT 'CCREPO', 0.5, 10 , 0.0516 FROM DUAL UNION ALL
SELECT 'CCREPO', 0.7, 9 , NULL FROM DUAL UNION ALL
SELECT 'CCREPO', 1, 5 , 0.0567 FROM DUAL UNION ALL
SELECT 'CCREPO', 1, 10 , 0.0487 FROM DUAL)
,ordered_input_1 as (
SELECT
i.*,
row_number() over ( partition by addon_product order by term_years) rn
FROM CLP_ADDON_CALC_STG i where (underlying_term_years < 9 or ( term_years < 0.7 and term_years > 0.7))
or (term_years = 0.7 and underlying_term_years = 9)order by term_years, underlying_term_years
-- where i.term_years
)
SELECT
addon_product,
term_years,
underlying_term_years,
addon,
term_years * regr_slope(addon, term_years) over ( partition by addon_product) +
regr_intercept(addon, term_years) over ( partition by addon_product)
as interpolated_value
FROM ordered_input_1
ORDER BY addon_product, term_years;
Now I am in situation where in I have to do interpolation on the interpolated values derived above for which I am not able to arrange the rows in order as required for the above analytic function.
I had referred to this link to get the rows in order ( Linear Interpolation in Oracle with special cases)
But for the next round of interpolation for which I would need the rows in some order
or I would need to a query (on the rows as seen in the image interpolated results ) which would do something like the below formula
((9-5)*0.05364 + (10-9)*0.0463)/(10-5) which would give me 0.052712
Any help would be greatly appreciated.
Thanks in advance,
Murali

Related

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

How to get records based on most occurring value?

I have following table and I want to get records where promotion is mostly occurring.
For example if I got two events
FREQ_VISITOR, value= 250
HIGH_SHOPPER, value= 320
Then Promo 1 and Promo 2 should come in result. Since these 2 promos exists mostly for every trigger and their given values.
Here's one option, based on what I understood:
SQL> with test (event_name, value, promotion) as
2 (select 'freq_visitor', 250, 'promo1' from dual union all
3 select 'high_shopper', 320, 'promo2' from dual union all
4 select 'freq_visitor', 250, 'promo3' from dual union all
5 select 'high_shopper', 320, 'promo1' from dual union all
6 select 'freq_visitor', 250, 'promo2' from dual
7 ),
8 cnt_promo as
9 (select promotion, count(*) cnt
10 from test
11 group by promotion
12 ),
13 most_promos as
14 (select max(cnt) max_cnt
15 from cnt_promo
16 )
17 select c.promotion
18 from cnt_promo c join most_promos m on c.cnt = m.max_cnt;
PROMOT
------
promo1
promo2
SQL>
This is a good candidate for analytic functions.
The below code is a bit longer than the self-join approach, and flows from the inside-out instead of a more traditional top-to-bottom direction. But this approach will likely be faster, since it only reads from the table once. And this approach is easier to debug than common table expressions, since you can highlight and run different inline views and watch the result set be built.
--Promotions with the highest counts.
select promotion
from
(
--RANK the promotion counts.
select promotion, promotion_count,
rank() over (order by promotion_count desc) promotion_rank
from
(
--Count of promos per event and value.
select promotion, count(*) promotion_count
from
(
--Test data
select 'freq_visitor' event_name, 250 value, 'promo1' promotion from dual union all
select 'high_shopper' event_name, 320 value, 'promo2' promotion from dual union all
select 'freq_visitor' event_name, 250 value, 'promo3' promotion from dual union all
select 'high_shopper' event_name, 320 value, 'promo1' promotion from dual union all
select 'freq_visitor' event_name, 250 value, 'promo2' promotion from dual
) test_data
group by promotion
) add_promo_count
) add_promo_rank
where promotion_rank = 1
order by promotion;

Oracle 11g - How to calculate the value of a number in range minimum or max

i need a help to get solution to my problem, Please.
I have a table like this :
ID Number
|6 |20.90 |
|7 |45.00 |
|8 |52.00 |
|9 |68.00 |
|10 |120.00 |
|11 |220.00 |
|12 |250.00 |
The first range is 0 - 20.90.
When the value is in the half, the value id is for the max range.
When i got value 20.91, i want to get "ID = 6".
If the value is 31.00, i want to get "ID = 6"
If the value is
33.95, i want to get "ID = 7".
if the value is 44.99, i want to get ID = 7
How i can do it? Is there a function that will do what I need?
If you want the record with a number that is closest to your input, then you can use this:
select *
from (
select *
from mytable
order by abs(number - my_input_number), id
)
where rownum < 2
The inner query selects all records, but orders them by the distance they have from your input number. This distance can be calculated with number - my_input_number. But that could be negative, so we take the absolute value of that. This result is not output; it is just used to order by. So records with smaller distances will come first.
Now we need just the first of those records, and that is what the outer query does with the typical Oracle reserved word rownum: it represents a sequence number for every record of the final result set (1, 2, 3, ...). The where clause will effectively filter away all records we do not want to see, leaving only one (with smallest distance).
As mathguy suggested in comments, the order by now also has a second value to order by in case the input value is right at the mid point between the two closest records. In that case the record with the lowest id value will be chosen.
This is a good illustration of the power of analytic functions:
with mytable ( id, value ) as (
select 6, 20.90 from dual union all
select 7, 45.00 from dual union all
select 8, 52.00 from dual union all
select 9, 68.00 from dual union all
select 10, 120.00 from dual union all
select 11, 220.00 from dual union all
select 12, 250.00 from dual
),
inputs ( x ) as (
select 0.00 from dual union all
select 20.91 from dual union all
select 31.00 from dual union all
select 33.95 from dual union all
select 44.99 from dual union all
select 68.00 from dual union all
select 32.95 from dual union all
select 400.11 from dual
)
-- End of test data (not part of the solution). SQL query begins BELOW THIS LINE
select val as x, new_id as closest_id
from (
select id, val,
last_value(id ignore nulls) over (order by val desc) as new_id
from (
select id, (value + lead(value) over (order by value))/2 as val
from mytable
union all
select null, x
from inputs
)
)
where id is null
order by x -- if needed
;
Output:
X CLOSEST_ID
------ ----------
0 6
20.91 6
31 6
32.95 6
33.95 7
44.99 7
68 9
400.11 12

Oracle SQL Select Query Getting Max Row As a Fraction of a Rollup Total

hoping I might be able to get some advise regarding Oracle SQL…
I have a table roughly as follows (there are more columns, but not necessary for this example)…
LOCATION USER VALUE
1 1 10
1 2 20
1 3 30
2 4 10
2 5 10
2 6 20
1 60
2 40
100
I’ve used rollup to get subtotals.
What I need to do is get the max(value) row for each location and express the max(value) as a percentage or fraction of the subtotal for each location
ie:
LOCATION USER FRAC
1 3 0.5
2 6 0.5
I could probably solve this using my limited knowledge of select queries, but am guessing there must be a fairly quick and slick method..
Thanks in advance :)
Solution using analytic functions
(Please note the WITH MY_TABLE AS serving only as dummy datasource)
WITH MY_TABLE AS
( SELECT 1 AS LOC_ID,1 AS USER_ID, 10 AS VAL FROM DUAL
UNION
SELECT 1,2,20 FROM DUAL
UNION
SELECT 1,3,30 FROM DUAL
UNION
SELECT 2,4,10 FROM DUAL
UNION
SELECT 2,5,10 FROM DUAL
UNION
SELECT 2,6,20 FROM DUAL
)
SELECT LOC_ID,
USER_ID,
RATIO_IN_LOC
FROM
(SELECT LOC_ID,
USER_ID,
RATIO_IN_LOC,
RANK() OVER (PARTITION BY LOC_ID ORDER BY RATIO_IN_LOC DESC) AS ORDER_IN_LOC
FROM
(SELECT LOC_ID,
USER_ID,
VAL,
VAL/SUM(VAL) OVER (PARTITION BY LOC_ID) AS RATIO_IN_LOC
FROM MY_TABLE
)
)
WHERE ORDER_IN_LOC = 1
ORDER BY LOC_ID,
USER_ID;
Result
LOC_ID USER_ID RATIO_IN_LOC
1 3 0,5
2 6 0,5
with inputs ( location, person, value ) as (
select 1, 1, 10 from dual union all
select 1, 2, 20 from dual union all
select 1, 3, 30 from dual union all
select 2, 4, 10 from dual union all
select 2, 5, 10 from dual union all
select 2, 6, 20 from dual
),
prep ( location, person, value, m_value, total ) as (
select location, person, value,
max(value) over (partition by location),
sum(value) over (partition by location)
from inputs
)
select location, person, round(value/total, 2) as frac
from prep
where value = m_value;
Notes: Your table exists already? Then skip everything from "inputs" to the comma; your query should begin with with prep (...) as ( ...
I changed user to person since user is a keyword in Oracle, you shouldn't use it for table or column names (actually you can't unless you use double quotes, which is a very poor practice).
The query will output two or three or more rows per location if there are ties at the top. Presumably this is what you desire.
Output:
LOCATION PERSON FRAC
---------- ---------- ----------
1 3 .5
2 6 .5

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

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

Resources