tags:

views:

154

answers:

4

This is a simplified version of a query I have. Say for each customer that has made an order, I want to know what percentage of their total order value was for green items.

There can't be multiple items in an order, but it's possible for the order value to be zero so I want to avoid division errors. (And no, I am not able to change the database in any way.)

What's the best way to do this? EDIT: Omitting zero-totals is fine actually, hence accepted answer.

SELECT order.customer,
  SUM
  (
    CASE items.color WHEN 'Green' THEN order.value
    ELSE 0 END
  ) * 100 / sum(order.value) AS percentage,
  SUM(order.value) AS total_value
FROM orders
  INNER JOIN item
    ON order.item_id = item.item_id
GROUP BY order.customer
+2  A: 
SELECT order.customer,
  SUM
  (
    CASE items.color WHEN 'Green' THEN order.value
    ELSE 0 END
  ) * 100 / CASE sum(order.value) WHEN 0 THEN 1 ELSE SUM(order.value) END AS percentage,
  SUM(order.value) AS total_value
FROM orders
  INNER JOIN item
    ON order.item_id = item.item_id
GROUP BY order.customer
Quassnoi
+2  A: 

Add

having sum(order.value) <> 0

After your group by

Binary Worrier
This may filter out some orders.
Quassnoi
Actually I think it would be better just to say "Where order.value <> 0" - that will filter out he records, eliminating the need for the "having" clause.
Brandon Montgomery
Thats true, but what are the chances that the user wants to see a report where it shows there were 0% green items sold to customers that didn't spend any money with us?
Binary Worrier
Low, which is why you'd filter those records out of the results. Either way will give you the same result, but I have a feeling the "having" clause is less efficient than the simple "where" clause.
Brandon Montgomery
Brandon: Yes, but as I commented on your question, the "where" clause is not sufficient.
Binary Worrier
Leaving out the items is fine, so I'll accept this, thanks. Brandon and Quassnoi's answers are also good.
nearly_lunchtime
Brandon: Yes, the having is less efficient, you are correct and it's a good point to illustrate.
Binary Worrier
+3  A: 

See here: SQL Server efficient handling of divide by zero

SQLMenace
+2  A: 

Can you just filter out the orders where order.value = 0?

Where
  order.value <> 0
Brandon Montgomery
Not sufficient, because the sum of order values for a customer may still be zero
Binary Worrier
OK, a customer buys 10 green widgets, decides they are too green and returns them, going else where to buy light green widgets. There are two orders for that customer, neither of which are Zero, but when combined for that customer, add to Zero. How does the "where order.value <> 0" help there?
Binary Worrier
Good point. Thanks for the clarification.
Brandon Montgomery