SQL query to multiply with earlier records factor - sql

I'm trying to select a record by ID, they all have the same base value, but different multipliers.
so i want the base value multiplied by whatever comes next like given image shows

Try this:
SELECT
a.*,
a.value * ( 1 + SUM(a.multiplier) OVER(
PARTITION BY id
) / 100 ) desired_column
FROM
aux a;
Output
ID VALUE MULTIPLIER DESIRED_COLUMN
1 120 2 126
1 120 3 126
2 110 4 123.2
2 110 8 123.2
If you want just one row per id, then go with this:
SELECT
a.id,
a.value * ( 1 + SUM(a.multiplier) / 100 ) desired_column
FROM
aux a
GROUP BY
a.id,
a.value;
Output
ID DESIRED_COLUMN
1 126
2 123.2

Are you looking for arithmetic?
select t.*, (value * (1.0 + multiplier / 100.0)) as calculated_value
from t;

Related

How do i select all columns, plus the result of the sum

I have this select:
"Select * from table" that return:
Id
Value
1
1
1
1
2
10
2
10
My goal is create a sum from each Value group by id like this:
Id
Value
Sum
1
1
2
1
1
2
2
10
20
2
10
20
I Have tried ways like:
SELECT Id,Value, (SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY IDRNC ) FROM Table v;
But the is not grouping by id.
Id
Value
Sum
1
1
1
1
1
1
2
10
10
2
10
10
Aggregation aggregates rows, reducing the number of records in the output. In this case you want to apply the result of a computation to each of your records, task carried out by the corresponding window function.
SELECT table.*, SUM(Value) OVER(PARTITION BY Id) AS sum_
FROM table
Check the demo here.
Your attempt looks correct.
Can you try the below query :
It works for me :
SELECT Id, Value,
(SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY ID) as sum
FROM Table v;
You can do it using inner join to join with selection grouped by id :
select t.*, sum
from _table t
inner join (
select id, sum(Value) as sum
from _table
group by id
) as s on s.id = t.id
You can check it here
Your select is ok if you adjust it just a little:
SELECT Id,Value, (SELECT SUM(Value) FROM Table V2 WHERE V2.Id= V.Id GROUP BY IDRNC ) FROM Table v;
GROUP BY IDRNC is a mistake and should be GROUP BY ID
you should give an alias to a sum column ...
subquery selecting the sum does not have to have self table alias to be compared with outer query that has one (this is not a mistake - works either way)
Test:
WITH
a_table (ID, VALUE) AS
(
Select 1, 1 From Dual Union All
Select 1, 1 From Dual Union All
Select 2, 10 From Dual Union All
Select 2, 10 From Dual
)
SELECT ID, VALUE, (SELECT SUM(VALUE) FROM a_table WHERE ID = v.ID GROUP BY ID) "ID_SUM" FROM a_table v;
ID VALUE ID_SUM
---------- ---------- ----------
1 1 2
1 1 2
2 10 20
2 10 20

make numeric values homonyms fractions in sql table

i have a table like this:
ID
num_A
num_B
1
1
168
2
1
4
2
5
24
2
6
24
3
1
36
So, num_A and num_B represent a fraction. That means for ID=1, i have 1/168, ID=2 ---> (1/4)+(5/24)+(6/24) = 17/24, ID=3 --> 1/36....
I need to add 2 columns, one with the sum(num_A) and one with the denominator num_B, for those with the same ID. So the example should be:
ID
num_A
num_B
sumA
denom_B
1
1
168
1
168
2
1
4
17
24
2
5
24
17
24
2
6
24
17
24
3
1
36
1
36
My problem is that i dont know how to calculate the denominator for each different fraction in postgres.
In general PostgreSQL provides the LCM function that returns the least common multiple (the smallest strictly positive number that is an integral multiple of both inputs), but it takes only two arguments and cannot be used to process rowset column values.
Thus, to get the LCM of rows with the same ID value, you can use a recursive CTE to process the rows one by one, using the LCM function with the LCM calculated in the previous step (in the first step equal to the value of num_B ) and the current value of num_B as arguments. This will produce the LCM value of all previous num_B and the current value for each row.
Finally, you can get the maximum (the last if to be exact, it would be the maximum anyway) calculated LCM value for rows grouped by ID and that will be the LCM for all num_B values ​​with the same ID.
The rest is simple - divide, multiply and sum.
Query:
WITH t_rn AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY num_b) AS rn FROM t
),
least_common_multiple AS (
WITH RECURSIVE least_multiples AS (
SELECT
id,
num_b,
num_b AS lm,
rn
FROM t_rn
WHERE rn = 1
UNION ALL
SELECT
t_rn.id,
t_rn.num_b,
LCM(t_rn.num_b, lm.lm),
t_rn.rn
FROM t_rn
JOIN least_multiples lm ON lm.id = t_rn.id AND t_rn.rn = lm.rn + 1
)
SELECT
id,
MAX(lm) AS lcm
FROM least_multiples
GROUP BY id
)
SELECT
t.*,
SUM(t.num_a * lm.lcm / t.num_b) OVER (PARTITION BY t.id) AS suma,
lm.lcm AS denom_b
FROM t
JOIN least_common_multiple lm ON t.id = lm.id
Output
id
num_a
num_b
suma
denom_b
1
1
168
1
168
2
1
4
17
24
2
5
24
17
24
2
6
24
17
24
3
1
36
1
36
DEMO
I think you are trying to simulate fraction addition,
Try the following query:
with find_mutiplication As
(
Select Id, num_a, num_b,
ROUND(EXP(SUM(LN(ABS(num_b))) over (partition by id))) as mutiplication,
ROUND(EXP(SUM(LN(ABS(num_b))) over (partition by id))) / num_b * num_a as unified
From mytable
)
,
calc as
(
Select *,
mutiplication/ GCD(mutiplication::int, SUM(unified::int)over (partition by id)) denom_B,
num_a * (mutiplication/ GCD(mutiplication::int, SUM(unified::int)over (partition by id)) / num_b) as dv
From find_mutiplication
)
Select id, num_a, num_b,
SUM(dv) Over (Partition By id) As sumA,
denom_b
From calc
Order By id
See demo from db<>fiddle.
To understand how the query works consider the following image:
where the ROUND(EXP(SUM(LN(num_b)) over (partition by id))) will find the multiplication of the dividends for each id. (According to this post)

How to create numbers range of numbers between two numbers?

So i have Table and i have Columns NumberMin(minimal number ) and i have NumberMax(maximal number)
i have many records i want to select all data and in new column i had numbers beetwen this number min and number max like this
this is table
ID Name NumberMin NumberMax
13 Jhon 10 14
and when i select i want to be like this
Name NumberMin NumberMax newcolum
Jhon 10 14 10
Jhon 10 14 11
Jhon 10 14 12
Jhon 10 14 13
i tried this code but didn't worked like this
;with numcte
AS
(
SELECT NumbMin as[SEQUENCE]
UNION all
SELECT Name,NumbMin,NumbMax,[SEQUENCE] + 1 FROM Table WHERE NumbMin <NumbMax
)
SELECT * FROM numcte
Yet another option is an ad-hoc tally table.
Not sure if you wanted to exclude the top value (14). If so, just remove the +1 in the Select top(...)
Example
Select A.*
,NewColumn = NumberMin+B.N-1
From YourTable A
Cross Apply (
Select Top (NumberMax-NumberMin+1) N=row_number() Over (Order By (Select NULL)) From master..spt_values n1, master..spt_values n2
) B
Returns
The problem with your query is that both the anchor and the recursive part of the query must have the same number of columns (and identical datatypes). Your anchor has just one column (numberMin), while the recursive part has 4 columns, so the query errors.
Consider:
with numcte as (
select id, name, numberMin, numberMax, numberMin newcol from mytable
union all
select id, name, numberMin, numberMax, newcol + 1
from numcte
where newcol < numberMax - 1
)
select * from numcte
The where condition prevents the last value of newcol to actually reach numberMax - that's a bit unusual, but that's what your desired result is showing.
Note that SQL Server by default restricts the number of iteration of a recursive query to 100. If you need to handle more than that, you need to add option (maxrecursion 0) at the end of the query.
You can use a recursive CTE to do this.
For example:
with
x as (
select ID, Name, NumberMin, NumberMax, NumberMin as cur from t
UNION ALL
select ID, Name, NumberMin, NumberMax, cur + 1
from x
where cur < NumberMax - 1
)
select * from x
Result:
ID Name NumberMin NumberMax cur
-- ---- --------- --------- ---
13 John 10 14 10
13 John 10 14 11
13 John 10 14 12
13 John 10 14 13
See running example at DB<>Fiddle.

How to get change points in oracle select query?

How can I select change points from this data set
1 0
2 0
3 0
4 100
5 100
6 100
7 100
8 0
9 0
10 0
11 100
12 100
13 0
14 0
15 0
I want this result
4 7 100
11 12 100
This query based on analytic functions lag() and lead() gives expected output:
select id, nid, point
from (
select id, point, p1, lead(id) over (order by id) nid
from (
select id, point,
decode(lag(point) over (order by id), point, 0, 1) p1,
decode(lead(point) over (order by id), point, 0, 2) p2
from test)
where p1<>0 or p2<>0)
where p1=1 and point<>0
SQLFiddle
Edit: You may want to change line 3 in case there only one row for changing point:
...
select id, point, p1,
case when p1=1 and p2=2 then id else lead(id) over (order by id) end nid
...
It would be simple to use ROW_NUMBER analytic function, MIN and MAX.
This is a frequently asked question about finding the interval/series of values and skip the gaps. I like the word given to it as Tabibitosan method by Aketi Jyuuzou.
For example,
SQL> SELECT MIN(A),
2 MAX(A),
3 b
4 FROM
5 ( SELECT a,b, a-Row_Number() over(order by a) AS rn FROM t WHERE b <> 0
6 )
7 GROUP BY rn,
8 b
9 ORDER BY MIN(a);
MIN(A) MAX(A) B
---------- ---------- ----------
4 7 100
11 12 100
SQL>

Oracle - theoretical sql query for create intervals

Is it possible to solve this situation by sql query in ORACLE?
I have a table like this:
TYPE UNIT
A 230
B 225
C 60
D 45
E 5
F 2
I need to separate units to the three(variable) 'same'(equally sized) intervals and foreach figure out the count? It means something like this:
0 - 77 -> 4
78 - 154 -> 0
155 - 230 -> 2
You can use the maximum value and a connect-by query to generate the upper and lower values for each range:
select ceil((level - 1) * int) as int_from,
floor(level * int) - 1 as int_to
from (select round(max(unit) / 3) as int from t42)
connect by level <= 3;
INT_FROM INT_TO
---------- ----------
0 76
77 153
154 230
And then do a left outer join to your original table to do the count for each range, so you get the zero value for the middle range:
with intervals as (
select ceil((level - 1) * int) as int_from,
floor(level * int) - 1 as int_to
from (select round(max(unit) / 3) as int from t42)
connect by level <= 3
)
select i.int_from || '-' || i.int_to as range,
count(t.unit)
from intervals i
left join t42 t
on t.unit between i.int_from and i.int_to
group by i.int_from, i.int_to
order by i.int_from;
RANGE COUNT(T.UNIT)
---------- -------------
0-76 4
77-153 0
154-230 2
Yes, this can be done in Oracle. The hard part is the definition of the bounds. You can use the maximum value and some arithmetic on a sequence with values of 1, 2, and 3.
After that, the rest is just a cross join and aggregation:
with bounds as (
select (case when n = 1 then 0
when n = 2 then trunc(maxu / 3)
else trunc(2 * maxu / 3)
end) as lowerbound,
(case when n = 1 then trunc(maxu / 3)
when n = 2 then trunc(2*maxu / 3)
else maxu
end) as upperbound
from (select 1 as n from dual union all select 2 from dual union all select 3 from dual
) n cross join
(select max(unit) as maxu from atable t)
)
select b.lowerbound || '-' || b.upperbound,
sum(case when units between b.lowerbound and b.upperbound then 1 else 0 end)
from atable t cross join
bounds b
group by b.lowerbound || '-' || b.upperbound;