Finding top 5 worst performing customers by salesperson - sql

I have a view that returns data as follows:
| salesman | customer | invoiced | budgeted | difference
|--------------|--------------|-------------|-------------|--------------
| Joe | ACME Ltd | 1000 | 2000 | -1 000
| Sam | Apple | 1500 | 1100 | +400
| Joe | Apple | 2000 | 2300 | -300
| Kim | ACME Ltd | 1000 | 1500 | -500
This is a snippet of of over 1500 rows that are returned. What I would like to do is return all rows by salesman showing that salespersons 5 worst customers sales. Each salesperson would therefore have 5 rows and each salesperson does sell to various customers who can be the same customer as another salesperson... right now I am looking at 5 worst customers by salesperson by value.
Any ideas on how I can achieve this?

Since one salesman can invoice the same company multiple times, you need to average the invoice amount across that group, then rank withing that partition and take the top five. If you are looking for the absolute worse sale per salesman then you would need to replace AVG with MIN.
SELECT
*
FROM
(
SELECT
salesman,
customer,
AverageInvoiced,
DescendingRank=DENSE_RANK() OVER(PARTITION BY salesman ORDER BY AverageInvoiced DESC)
FROM
(
SELECT
salesman,
customer,
AverageInvoiced=AVG(invoiced)
FROM
Table
WHERE
GROUP BY
salesman,
customer
)
)AS A
WHERE
DescendingRank<=5

I think you can use this
TRy This
SELECT
*
FROM
(
SELECT
salesman,
customer,
AverageDiffrence,
DescendingRank=DENSE_RANK() OVER(PARTITION BY salesman ORDER BY AverageDiffrence DESC)
FROM
(
SELECT
salesman,
customer,
AverageDiffrence=AVG(difference)
FROM
ireports_salesman_variance
WHERE
GROUP BY
salesman,
customer
)
)AS A
WHERE
DescendingRank<=5

Related

Sum Total of Distinct Items In Table

I have a table of transactions. One column is for the vendor ID, and one column is for the amount due. [There are other columns, but they aren't relevant]
id | amount | custid
23 | -31.32 | 904424
24 | -19.94 | 646744
25 | -4.77 | 904424
26 | -29.40 | 972979
I want to run a query that delivers the total for each distinct customer ID.
The goal is to determine how much each customer is owed.
That's basic aggregation:
select custid, sum(amount) total_amount
from mytable
group by custid

Aggregating column values based on range

I'm new to SQL and stackoverflow, forgive if my question is trivial. I have record of customers purchase quantities in a table, so I want a count of customers whose purchase fall in a range.
TABLE:
+-------------+----------------+
| customer_id | order_quantity |
+-------------+----------------+
| 123 | 10000 |
| 143 | 5000 |
| 999 | 200000 |
| 555 | 50000 |
+-------------+----------------+
The goal is to count how many customers buy < 5000, between 5000-50000 and 50000-100000 order quantities.
I used:
SELECT customer_id,
CASE
WHEN COUNT(order_quantity) < 5000
....
FROM purchases
Which isn't correct (don't even work).
You can use:
select (case when order_quantity < 5000 then '[0-5000)'
when order_quantity < 10000 then '[5000-10000)'
else '10000+'
end) as grp,
count(*) as num_purchases,
count(distinct customer_id) as num_customers
from t
group by grp
order by min(order_quantity);
If a customer makes more than one purchase in a given group, it is not clear if you want to count the number of purchases or the number of customers. This does both.

Sum up any pair of pizza that are in the same restaurant in SQL

Conditions:
Budget of $40
Buy 2 distinct pizza from the same restaurant
Expected Results: List of restaurants that fulfill the above conditions
Database schema: Customers(cname, area), Restaurants(rname, area), Pizzas(pizza), Sells(rname,pizza,price), Likes(cname, pizza)
Sells table
| rname | Pizzas | Price |
------------------------------
| rname1 | Hawaiian | $10 |
| rname2 | Hawaiian | $20 |
| rname2 | Pizza3 | $20 |
| rname3 | Pizza4 | $20 |
So in this case, rname2 will be the answer since $20+$20 = $40. And they are from the same restaurant and the two pizzas are distinct.
SQL Query:
SELECT s.rname
FROM Sells s
WHERE s.price < 40 -- Max $40 only. How to total up price of 2 pizzas here?
GROUP BY s.rname
HAVING COUNT(DISTINCT s.pizza)>=2
Update:
My issue is that i want to check if there are 2 distinct pizza that does not exceed the budget of $40 in each of the restaurants.
Not the sum of the whole column.
You want a self join:
select s1.rname, s1.pizza, s2.pizza
from sales s1 join
sales s2
on s1.rname = s2.rname and s1.pizza < s2.pizza
where s1.price + s2.price = 40;
"Budget" suggests <= for the comparison. But the question itself has $20+$20 = $40, suggesting that you really intend equality.

Top 2 offers with sum of all offers

Can someone please tell how can I get the results as below.
Using dense_rank function where rank <=2 will give me top 2 offers.
I am also looking to get 'total_offer' which should be sum of 'offer1' and 'offer2'. when there is no offer2 ( eg:taurus) 'total offer' should be 'offer1' and 'null' for 'offer2'
Input:
customer make zipcode offer notes
mark focus 101 250 cash
mark focus 101 2500 appreciation cash
mark focus 101 1000 cash
mark focus 101 1500 cash offer
henry 520i 21405 500 cash offer
henry 520i 21405 100 cash
henry 520i 21405 750 appreciation cash
henry 520i 21405 100 cash
mark taurus 48360 250 appreciation cash
mark mustang 730 500 cash
mark mustang 730 1000 Cash offer
mark mustang 730 1250 appreciation cash
Desired Output:
| CUSTOMER | MAKE | ZIPCODE | TOP_OFFER1 | notes1 | TOP_OFFER2 | notes2 | Total_offer |
| henry | 520i | 21405 | 750 | appreciation cash | 500 | cash offer | 1250
| mark | focus | 101 2500 | appreciation cash | 1500 | cash offer | 4000
| mark | mustang | 730 | 1250 | appreciation cash | 1000 | cash offer | 2250
| mark | taurus | 48360 | 250 | appreciation cash | NULL | 250 |
Thanks
PS:
The link below tells me that dense_rank need to be performed to get top 2 offers.
(Using a pl-sql procedure or cursor to select top 3 rank)
with x as
(select row_number() over(partition by customer,make order by offer desc) rn,
customer, make, zipcode, offer from tablename)
, y as (select customer, make, zipcode, offer from x where rn <=2)
, z as (select customer, make, zipcode,
case when rn = 1 then offer else 0 end as offer_1,
case when rn = 2 then offer else 0 end as offer_2
from y)
select customer, make, zipcode, offer_1, offer_2, offer_1+offer_2 total_offer
from z
This makes use of recursive cte's to accomplish your task.
Try this code...
WITH subqueryfactoring AS
(SELECT customer,
make ,
zipcode ,
offer,
lead(offer) over (partition BY customer, make , zipcode order by offer DESC) SecondLeadValue,
row_number() over (partition BY customer, make , zipcode order by offer DESC ) rownumber
FROM abc1
)
SELECT customer,
make ,
zipcode,
offer "Top Offer1 ",
SecondLeadValue "Top offer 2",
offer + COALESCE(SecondLeadValue,0) "Total Offer"
FROM subqueryfactoring
WHERE rownumber<2;
You better use ROW_NUMBER instead of DENSE_RANK (which might return more than two rows) plus a LEAD to find the 2nd highest value
select customer, make, zipcode,
TOP_OFFER1,
TOP_OFFER2,
TOP_OFFER1 + coalesce(TOP_OFFER2,0) as Total_offer
from
(
select customer, make, zipcode,
offer as TOP_OFFER1, -- max offer
lead(offer) over (partition by customer, make, zipped
order by offer desc) as TOP_OFFER2, -- 2nd highest offer
row_number() over (partition by customer, make, zipped
order by offer desc) as rn
from tab
) dt
where rn = 1 -- only the row with the highest offer

SQL: Select distinct sum of column with max(column)

I have a salary table like this:
id | person_id | start_date | pay
1 | 1234 | 2012-01-01 | 3000
2 | 1234 | 2012-05-01 | 3500
3 | 5678 | 2012-01-01 | 5000
4 | 5678 | 2013-01-01 | 6000
5 | 9101 | 2012-09-01 | 2000
6 | 9101 | 2014-04-01 | 3000
7 | 9101 | 2011-01-01 | 1500
and so on...
Now I want to query the sum of the salaries of a specific month for all persons of a company.
I already have the ids of the persons who worked in the specific month in the specific company, so I can do something like WHERE person_id IN (...)
I have some problems with the salaries query though. The result for e.g. the month 2012-08 should be:
10000
which is 3500+5000+1500.
So I need to find the summed up pay value (for all persons in the IN clause) for the maximum start_date <= the specific month.
I tried various INNER JOINS but it's been a long day and I can't think straight at the moment.
Any hint is highly appreciated.
You need to get the active record. This following does this by calculating the max start date before the month in question:
select sum(s.pay)
from (select person_id, max(start_date) as maxstartdate
from salary
where person_id in ( . . . ) and
start_date < <first day of month of interest>
group by person_id
) p join
salary s
on s.person_id = p.person_id and
s.maxstartdate = p.start_date
You need to fill in the month and list of ids.
You can also do this with ranking functions, but you don't specify which SQL engine you are using.
You have to use group by for these things....
select person_id,sum(pay) from salary where person_id in(...) group by person_id
may it will helps you.....