tags:

views:

1502

answers:

4

I have an typical CUSTOMER/ORDERS set of tables and I want to display the total percentage of sales a particular customer is responsible for. I can get the total number of orders in the system like so:

SELECT COUNT(order_id) FROM orders

And I can get the the total number of orders made by the customer like so:

SELECT COUNT(order_id) FROM orders WHERE cust_id = 541

How can I combine these into a single query that returns the percentage of sales for a particular customer? Thanks!

+5  A: 

MySQL:

SELECT ROUND(
  100.0 * (
      SUM(IF(cust_id = 541, 1, 0)) / COUNT(order_id)
  ), 1) AS percent_total
FROM orders;

Edit

I guess it helps if I would have noticed the postgres tag. I thought it was a MySQL question.

PostgreSQL:

SELECT ROUND(
  100.0 * (
      SUM(CASE WHEN cust_id = 541 THEN 1 ELSE 0 END) / COUNT(order_id)
  ), 1) AS percent_total
FROM orders;

P.S. My PostgreSQL is rusty, so if the MySQL query works on PostgreSQL I'd like to know :)

Edit 2

I can't stress enough to be wary of the count(*) suggestion below. You generally want to avoid this with PostgreSQL.

hobodave
A: 

One solution is to use a nested query-

SELECT count(*) / (SELECT count(*) FROM orders)
FROM orders
WHERE cust_id = 541
Rob Elliott
Unnecessary to involve a subquery for something this trivial.
hobodave
+1 for one time queries, this is easier/faster to type and conceptualize than the hobodave's sumif() form.
Wadih M.
No, this is a terrible terrible thing. In PostgreSQL count(*) is not O(1) as it is in MySQL. This query would require two full table scans. This is unnecessary and grows prohibitively worse as the table size increases.
hobodave
I should correct that to read "as it is with MyISAM tables in MySQL".
hobodave
I'd also like to add: "easier to type" has got to be one of the worst reasons to do something. Unless you're in some sort of competition to complete as much code in as little time as possible.
hobodave
hobodave: no, it will not require 2 full table scans. it will require 1 full table scan, and 1 index scan (assuming there is index on cust_id).
depesz
A more simplet one will be select cust_id, ( count(*)/(select count(1) from orders ) * 100 ) from orders group by cust_id;
Roopesh Majeti
@depesz: you are correct, I realized this after I posted. :)
hobodave
@Roopesh: Not quite what he's asking for, but yes that would get the percentage for every customer. +1
hobodave
A: 
select max([order].customerid) customer_id, count(orderid) customer_orders, (select count(orderid) from [order]) as total_orders,
100.0 * (count(orderid))/(select count(orderid) from [order])
from [order] inner join customer
on [order].customerid = customer.customerid
group by [order].customerid

To illustrate the flow, I have included more columns than you need to see in the final result set. Holding the count(order_id) in a temporary variable will be more efficient. I'm not used to postgres, I hope this works with minimal modification.

keni
-1 when I get my daily vote count reset. There is no need to do a JOIN and GROUP BY for something as simple as this.
hobodave
A: 

select abc.item_name,sum(amount) as total from (select a.item_id,d.applicablefrom,a.item_name,a.final_item_status,d.rate,c.item_name as sub_item_name, b.sub_item_qty as itemqty, (b.sub_item_qty * d.rate)as amount from tblitem_master a,tblitem_master c,tblitem_bom_master b, (select rate,applicablefrom,itemid from tblperiodrates where applicablefrom= (select max(applicablefrom) from tblperiodrates where applicablefrom<='2005-5-18'))as d where a.item_id = b.item_id And b.sub_item_id = c.item_id and b.sub_item_id = d.itemid and a.final_item_status='f') as abc group by abc.item_name

vikram