Percentage from TOTAL in SQL [duplicate] - sql

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.

Related

SQL Bigquery fill null values with calculated from certain factor

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

Decreasing of the sum by percentage (subtraction of percentage) SQL

Substraction of percentage
I have got a table where is one record. Table looks like:
cust_code, SUM
1 25
I need to calculate a subtraction like this.
cust_code, ID, SUM
1 1 25
1 2 23
1 3 21.16
1 4 19.47
1 5 17.91
1 6 16.48
1 7 15.16
1 8 13.95
. . .
. . .
. . .
1 15 7.78
where value of sum in record 2 is subtracted by 8% of record 1,
value of sum in record 3 is subtracted by 8% of record 2,
value of sum in record 4 is subtracted by 8% of record 3, etc.
Max ID will be 15.
It should be single query, I can use any additional external table (containing for example simple counter from 0 to 15).
Best regards,
Volcano
Easy to do with a recursive CTE:
WITH cte AS
(SELECT cust_code, 1 AS id, sum FROM cust
UNION ALL
SELECT cust_code, id + 1, sum * 0.92 FROM cte WHERE id < 15)
SELECT * FROM cte ORDER BY id;
cust_code id sum
---------- ---------- ----------
1 1 25.0
1 2 23.0
1 3 21.16
1 4 19.4672
1 5 17.909824
1 6 16.4770380
1 7 15.1588750
1 8 13.9461650
1 9 12.8304718
1 10 11.8040340
1 11 10.8597113
1 12 9.99093444
1 13 9.19165969
1 14 8.45632691
1 15 7.77982076

SQL join query for a view with sum of columns across 3 tables

I have 3 tables as below
Table - travel_requests
id industry_id travel_cost stay_cost other_cost
1 2 1000 500 200
2 4 4000 100 200
3 5 3000 0 400
4 1 3000 250 100
5 1 200 100 75
Table - industry_tech_region
id industry_name
1 Auto
2 Aero
3 Machinery
4 Education
5 MTV
Table - industry_allocation
id industry_id allocation
1 1 500000
2 2 300000
3 3 500000
4 4 300000
5 5 500000
6 1 200000
I want to create a view which has 3 columns
industry_name, total_costs, total_allocation
I created a view as below
SELECT industry_tech_region.industry_name,
SUM(travel_requests.travel_cost + travel_requests.stay_cost + travel_requests.other_cost) AS total_cost,
SUM(industry_allocation.allocation) AS total_allocation
FROM industry_tech_region
INNER JOIN industry_allocation
ON industry_tech_region.id = industry_allocation.industry_id
INNER JOIN travel_requests
ON industry_tech_region.id = travel_requests.industry_id
GROUP BY industry_tech_region.industry_name
But the result I get is as below which is incorrect
industry_name total_cost total_allocation
Aero 1700 300000
Auto 7450 1400000 (wrong should be 3725 and 700000)
Education 4300 300000
MTV 3400 500000
This is probably happening because there are 2 entries for industry_id 1 in the travel_requests table. But they should be counted only once.
Please let me know how do we correct the view statement.
Also I want to add another column in view which is remaining_allocation which is difference of total_allocation and total_cost for each industry.
you shoud join the sum (and not sum the join)
select
a.industry_name
, t1.total_cost
, t2.total_allocation
from dbo.industry_tech_region a
left join (
select dbo.travel_requests.industry_id
, SUM(dbo.travel_requests.travel_cost + dbo.travel_requests.stay_cost + dbo.travel_requests.other_cost) AS total_cost
FROM bo.travel_requests
group by dbo.travel_requests.industry_id
) t1 on a.id = t1.industry_id
left join (
select dbo.industry_allocation.industry_id
, SUM(dbo.industry_allocation.allocation) AS total_allocation
from dbo.industry_allocation
group by dbo.industry_allocation.industry_id
) t2 on a.id = t2.industry_id
this happen because you have two entry for the industry_id 1 and then the row are joined two time if you use the subquery for aggreated the row this can't happen ...
I have used left join because seems that not all the industry_id match for the 3 tables ..
You can use this approach too (without the ORDER BY because views do not allow it).
;WITH q AS (
SELECT industry_id
, sum(allocation) AS total_allocation
FROM #industry_allocation
GROUP BY industry_id
)
SELECT #industry_tech_region.industry_name
, isnull(SUM(#travel_request.travel_cost
+ #travel_request.stay_cost
+ #travel_request.other_cost),0.0) AS total_cost
,q.total_allocation AS total_allocation
FROM #industry_tech_region
LEFT JOIN q ON #industry_tech_region.id = q.industry_id
LEFT JOIN #travel_request ON #industry_tech_region.id = #travel_request.industry_id
GROUP BY #industry_tech_region.industry_name,q.total_allocation
ORDER BY industry_name

Conditionally iterating through each value in a column

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

Oracle SQL find row crossing limit

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);