I want to fill null value with a new price value. The new price value will calculated from the other product available price (same product) times the factor.
given table,
Prod | unit | factor | price
abc X 1 24000
abc Y 12 NULL
xyz X 1 NULL
xyz y 5 60000
xyz Z 20 NULL
that formula that comes to mind
null price = avail same prod price * it's factor/null price factor
with the existing table above, examples price formula will be
'abc Y price' = 20000 * 1 / 12 = 2000 (avail price is abc X)
'xyz X price' = 60000 * 5 / 1 = 300000 (avail price is xyz Y)
'xyz Z price' = 60000 * 5 / 20 = 15000 (avail price is xyz Y)
is there any way i can do this?
I think this does what you want:
select t.*,
coalesce(price,
max(price * factor) over (partition by prod) / factor
) as calculated_price
from t;
This replaces NULL prices with the maximum price * factor for the product -- then divided by the factor on the given row.
Below is for BigQuery Standard SQL
if a product has 2 or more price list, just fill the null with the lowest factor
#standardSQL
SELECT t.* REPLACE(IFNULL(t.price, t.factor * p.price / p.factor) AS price)
FROM `project.dataset.table` t
LEFT JOIN (
SELECT prod, ARRAY_AGG(STRUCT(price, factor) ORDER BY factor LIMIT 1)[SAFE_OFFSET(0)].*
FROM `project.dataset.table`
WHERE NOT price IS NULL
GROUP BY prod
) p
USING(prod)
If to apply to sample from your question - result is
Row prod unit factor price
1 abc X 1 24000.0
2 abc Y 12 288000.0
3 xyz X 1 12000.0
4 xyz Y 5 60000.0
5 xyz Z 20 240000.0
Note: it looks like in your formula you need to reverse factors - for example 60000 * 20 / 5 - not sure, but this looks more logical for me. If I am wrong you can adjust t.factor * p.price / p.factor and use p.factor * p.price / t.factor instead
In this case result will be (which matches what you expected but as I said already I suspect is wrong -but it is up to you obviously)
Row prod unit factor price
1 abc X 1 24000.0
2 abc Y 12 2000.0
3 xyz X 1 300000.0
4 xyz Y 5 60000.0
5 xyz Z 20 15000.0
Related
This question already has an answer here:
Percentage SQL Oracle
(1 answer)
Closed 1 year ago.
there is any way to calculate the first 80% percentage
select
testoo.ttamount,
egct.Category_name,
SUM(pola.LIST_PRICE * nvl(pola.QUANTITY,1)) * NVL(poh.RATE,1)
Line_amount,
ROUND ( SUM((pola.LIST_PRICE * nvl(pola.QUANTITY,1)) * NVL(poh.RATE,1)*100) / (testoo.ttamount) , 2 ) PERCENTAGE,
poh.CURRENCY_CODE
FROM
(SELECT
SUM(test.line_amount) TTAmount
FROM
( select
egct.Category_name,
SUM(pola.LIST_PRICE * nvl(pola.QUANTITY,1)) * NVL(poh.RATE,1)
Line_amount,
poh.CURRENCY_CODE
from EGP_CATEGORIES_TL egct,
PO_LINES_ALL pola,
PO_HEADERS_ALL poh
where
egct.category_ID=pola.category_ID
AND pola.po_header_id = poh.po_header_id
AND LANGUAGE='US'
AND TYPE_LOOKUP_CODE='STANDARD'
AND poh.APPROVED_FLAG='Y'
group by
egct.Category_name,
poh.CURRENCY_CODE,
poh.RATE ) Test ) Testoo,
EGP_CATEGORIES_TL egct,
PO_LINES_ALL pola,
PO_HEADERS_ALL poh
where
egct.category_ID=pola.category_ID
AND pola.po_header_id = poh.po_header_id
AND LANGUAGE='US'
AND TYPE_LOOKUP_CODE='STANDARD'
AND poh.APPROVED_FLAG='Y'
group by
egct.Category_name,
poh.RATE,
testoo.ttamount,
poh.CURRENCY_CODE
order by
Line_amount desc
for example the output
Category Percentage
1 32%
2 20%
3 20%
4 10%
5 18%
I want to get the high percentage which the percentage of it about 80 %
so the output will be
Category Percentage
1 32%
2 20%
3 20%
4 10%
5 18%
thanks.
You don't even need to calculate each percentage:
with t(x) as (
select * from table(sys.odcinumberlist(1,1,2,2,3,3,4,4,5,5))
)
select *
from (
select
x,
ratio_to_report(x)over() rtr,
percent_rank()over(order by x) pr
from t
)
where pr<=0.8;
Results:
X RTR PR
---------- ---------- ----------
1 .033333333 0
1 .033333333 0
2 .066666667 .222222222
2 .066666667 .222222222
3 .1 .444444444
3 .1 .444444444
4 .133333333 .666666667
4 .133333333 .666666667
8 rows selected.
Another variant for cumulative percentage filter:
select *
from (
select v.*, 100*sum(rtr)over(order by r) cumulative_percentage
from (
select
rownum r,
column_value val,
ratio_to_report(column_value) over() rtr
from table(sys.odcinumberlist(10,40,30,20))
) v
)
where cumulative_percentage<=80;
R VAL RTR CUMULATIVE_PERCENTAGE
---------- ---------- ---------- ---------------------
1 10 .1 10
2 40 .4 50
3 30 .3 80
3 rows selected.
In PostgreSQL, how can I get the average of all other rows (e.g., "val") in the same group (e.g., "retailer") while still outputting all rows?
For example, below, I want to get the percentage of the val column per row compared to all other rows with the same category. And I want to do this for each category.
Original table:
id | category | val
----------------------------
1 retailer 3
2 retailer 2
3 customer 1
4 retailer 5
5 customer 7
Example:
id | category | val | output
----------------------------
1 retailer 3 .3 (retailer1 value + all other retailer values / total values of retailers)
2 retailer 2 .2 (retailer2 value + all other retailer values / total values of retailers)
3 customer 1 .125 (1 / 1 + 7)
4 retailer 5 .5 (5 / 3 + 2 + 5)
5 customer 7 .875 (7 / 1 + 7)
Complete output:
id | category | val | output
----------------------------
1 retailer 3 .3
2 retailer 2 .2
3 customer 1 .125
4 retailer 5 .5
5 customer 7 .875
Use window functions:
select t.*, val::numeric / nullif(sum(val) over(partition by category), 0) res
from mytable t
The window sum() computes the total val over rows having the same category.
Notes:
it looks like val is an integer; if so, we need to cast at least one of the values to a decimal to avoid integer division
nullif() avoids the division by zero error if all categories have 0 values
I've put together a small database to keep track of some accumulator bets that a few of my colleagues and I place during the football season. Now I need to write a function to calculate the winnings for each selection. The key table is selection with the key fields for the function being odds and result_id where a result_id of 1 is a win. The stake is stored in the bet table. Below is the selection table which has two winners for bet_id 1, so the resulting equation would be ((#stake * 1.40) * 1.40). Is there a way using a cursor or a set based method to generate this value?
bet_id punter_id team_id odds result_id ground_id
1 1 24 1.40 1 1
1 1 48 1.60 2 1
1 1 89 1.60 2 1
1 2 8 1.40 1 1
1 2 11 1.60 2 1
1 2 107 1.60 2 1
Assuming you join on bet_id:
CREATE TABLE bet (bet_id int NOT NULL PRIMARY KEY,
stake float NOT NULL); -- or some floating point number type
To multiply a group we use the following relationship:
log( a * b * c ) = log(a) + log(b) + log(c)
And therefore for multiplication
a * b * c = exp( log( a * b * c ) ) = exp( sum( log(.) ) )
To calculate the factors
bet_id | odds_factor
1 | 1.40 * 1.40 = 1.96
we use the Common Table Expression CTE in this query
WITH factor( bet_id, odds_factor ) AS
( SELECT bet_id, exp( sum( log( odds ) ) )
FROM selection
WHERE result_id = 1 -- only winning odds in the grouping
GROUP BY bet_id )
SELECT b.bet_id,
b.stake,
f.odds_factor,
b.stake * f.odds_factor AS "total_odds"
FROM bet b
INNER JOIN factor f
ON b.bet_id = f.bet_id
-- ORDER BY b.bet_id -- optional ordering for readability
which should yield (untested)
bet_id | stake | odds_factor | total_odds
1 | 10.0 | 1.96 | 19.6
Think this is as simple as:
SELECT B.BET_ID,
S.PUNTER_ID,
((B.stake * S.odds) * S.odds)
FROM BET AS B
INNER JOIN SELECTION AS S ON B.Bet_id = S.Bet_id
WHERE S.result_id = 1
Given a table like this
id total_cost margin
a 2 10%
b 4 15%
c 6 4%
x 7 90%
y 8 13%
z 9 0%
Where the total cost is defined as a running aggregate of some positive column, so it's always sorted.
I need to find out in a single SQL command (needs to be efficient) the average margin where cost first exceeds or equals a number X.
i.e. given X = 7.5
I need to find the average margin where total_cost first exceeds or equal to 7.5. In this case the condition would be applied to the first 5 columns since
id total_cost margin
y 8 13%
is the first column where total_cost exceeds 7.5. The result would be
avg(10%, 15%, 4%, 90%, 13%)
Use the window function lag():
select id, total_cost, margin
from (
select *, lag(total_cost) over (order by total_cost) prev_total_cost
from the_table
) s
where coalesce(prev_total_cost, 0) < 7.5
id | total_cost | margin
----+------------+--------
a | 2 | 0.10
b | 4 | 0.15
c | 6 | 0.04
x | 7 | 0.90
y | 8 | 0.13
(5 rows)
To get the average:
select avg(margin)
from (
select *, lag(total_cost) over (order by total_cost) prev_total_cost
from the_table
) s
where coalesce(prev_total_cost, 0) < 7.5
avg
------------------------
0.26400000000000000000
(1 row)
I have a table which has four columns as below
ID.
SUB_ID. one ID will have multiple SUB_IDs
Revenue
PAY where values of Pay is always less than or equal to Revenue
select * from Table A order by ID , SUB_ID will have data as below
ID SUB_ID REVENUE PAY
100 1 10 8
100 2 12 9
100 3 9 7
100 4 11 11
101 1 6 5
101 2 4 4
101 3 3 2
101 4 8 7
101 5 4 3
101 6 3 3
I have constant LIMIT value 20 . Now I need to find the SUB_ID which Revenue crosses the LIMIT when doing consecutive SUM using SUB_ID(increasing order) for each ID and then find total Pay ##. In this example
for ID 100 Limit is crossed by SUB ID 2 (10+12) . So total Pay
is 17 (8+9)
for ID 101 Limit is crossed by SUB ID 4
(6+4+3+8) . So total Pay is 18 (5+4+2+7)
Basically I need to find the row which crosses the Limit.
Fiddle: http://sqlfiddle.com/#!4/4f12a/4/0
with sub as
(select x.*,
sum(revenue) over(partition by id order by sub_id) as run_rev,
sum(pay) over(partition by id order by sub_id) as run_pay
from tbl x)
select *
from sub s
where s.run_rev = (select min(x.run_rev)
from sub x
where x.id = s.id
and x.run_rev > 20);