Reputation: 87
I have a table with multiple rows, each of which contains these four columns:
product | price_instore | price_pickup | price_delivery | price_ship |
---|---|---|---|---|
1 | $13.00 | $13.50 | $14.50 | $18.00. |
2 | $4.00 | $4.00 | NULL | NULL |
3 | $10.00 | $10.00 | $12.00 | NULL |
I'd like to have a fifth column average_price that gives the average price for a product, but does not count NULLS towards the sum price, or towards the count used to divide the average.
So average price of product 1: ($13+$13.50+$14.50+$18)/4=$14.75
Average price of product 2: ($4+$4)/2 = $4.00
Average price of product 3: ($10+$10+$12)/3 = $10.67
Is there any way to do this is SQL? I've tried subqueries such as the one below without success:
(select coalesce((PRICE_INSTORE + PRICE_PICKUP + PRICE_DELIVERY + PRICE_SHIP) / 4,
PRICE_INSTORE, PRICE_PICKUP, PRICE_DELIVERY, PRICE_SHIP)
but then I only get one price if any of them are null
Upvotes: 1
Views: 2737
Reputation: 621
Try this
select coalesce (PRICE_INSTORE, 0 ) + coalesce (PRICE_PICKUP, 0) + coalesce (PRICE_DELIVERY , 0) + coalesce (PRICE_SHIP , 0) /
((case when PRICE_INSTORE is null then 0 else 1 end) + (case when PRICE_PICKUP is null then 0 else 1 end) +
(case when PRICE_DELIVERY is null then 0 else 1 end) + (case when PRICE_SHIP is null then 0 else 1 end) )
from product
Upvotes: 1
Reputation: 5803
This one is probably the easiest to digest. Performance shouldn't be too bad unless you have a very large table that is also, not indexed
with cte (product, prices) as
(select product, price_instore from t union all
select product, price_pickup from t union all
select product, price_delivery from t union all
select product, price_ship from t)
select product, avg(prices)
from cte
group by product;
You an either use the output as is, or wrap it around another CTE and use that to join on your original table to get the averages
Upvotes: 1
Reputation: 542
try this:
select coalesce(PRICE_INSTORE,0) + coalesce(PRICE_PICKUP,0) + coalesce(PRICE_DELIVERY,0) + coalesce(PRICE_SHIP,0)) / 4
Upvotes: 1
Reputation: 15614
select
*,
(select avg(x) from unnest(array[price_instore,price_pickup,price_delivery,price_ship]) as x) as avg_price
from
your_table;
Upvotes: 3
Reputation: 1269483
One method is a lateral join:
select t.*, avg_price
from t cross join lateral
(select avg(price) as avg_price
from (values (price_instore), (price_pickup), (price_delivery), (price_ship)
) v(price)
) x
Upvotes: 1
Reputation: 12494
I'm drunk, so there's probably a much better way to do this than pivoting, but I cannot see it now with the room spinning around me like it is.
with j as (
select product, to_jsonb(mytable) - 'product' as jdata
from mytable
)
select j.product, avg(e.value::numeric) as avg_price
from j
cross join lateral jsonb_each(j.jdata) as e(key, value)
where e.value is not null
group by j.product.
Upvotes: 2