Reputation: 1002
I have a SQL table (temp2) like this:
I want to calculate the balance*rate/sum(balance) for each cat
So, my desired output would be something like this:
To get this output, I used following code:
DROP TABLE IF EXISTS temp3;
create table temp3 as select cat, balance * rate /sum(balance) as prod from temp2
group by cat
select temp2.emp_id, temp2.cat,temp2.balance, temp2.rate , temp3.prod from temp2
left outer join temp3 on temp2.cat=temp3.cat
So here I have created a new table to get the answer. Will there be an easier way to get the same results?
Upvotes: 0
Views: 41
Reputation: 52549
You actually don't need a join or subquery at all thanks to window functions:
SELECT emp_id, cat, balance, rate,
balance * rate / sum(balance) OVER (PARTITION BY cat) AS prod
FROM temp2
ORDER BY emp_id;
gives
emp_id cat balance rate prod
------ --- ------- ---- ------------------
1 1 1000.0 0.25 0.0625
2 3 1250.0 0.25 0.0568181818181818
3 2 1500.0 0.25 0.0681818181818182
4 1 1000.0 0.25 0.0625
5 2 1250.0 0.25 0.0568181818181818
6 3 1500.0 0.25 0.0681818181818182
100 1 1000.0 0.25 0.0625
101 3 1250.0 0.25 0.0568181818181818
102 2 1500.0 0.25 0.0681818181818182
103 1 1000.0 0.25 0.0625
104 2 1250.0 0.25 0.0568181818181818
105 3 1500.0 0.25 0.0681818181818182
(Create an index on temp2.cat
for best performance).
This is also more accurate; both yours and Barmar's uses balance
and rate
in the grouped query without including those values in the GROUP BY
clause - that's an error in most databases, but Sqlite will pick a random row from the group to use as the values, which when different rows in the group have different values for them, will throw off the final calculations. To do it properly with grouping (If, for example, you're using an old database version that doesn't support window functions), you need something like
SELECT t2.emp_id, t2.cat, t2.balance, t2.balance * t2.rate / t3.sumbalance AS prod
FROM temp2 AS t2
JOIN (SELECT cat, sum(balance) AS sumbalance
FROM temp2
GROUP BY cat) AS t3
ON t2.cat = t3.cat
ORDER BY t2.emp_id;
Upvotes: 1
Reputation: 782098
There's no need for the new table unless you need to refer to it in multiple queries. You can just join with a subquery.
SELECT t2.emp_id, t2.cat, t2.balance, t2.rate, t3.prod
FROM temp2 AS t2
JOIN (
SELECT cat, balance * rate /sum(balance) AS prod
FROM temp2
GROUP BY cat
) AS t3 ON t2.cat = t3.cat
There's no need to use LEFT JOIN
. Since the subquery gets cat
from the same table, there can't be any non-matching rows.
Sometimes it's useful to create the new table so you can add an index for performance reasons.
Upvotes: 1