How to get the top performing employees from each Region? - sql

I have a table Sales with three columns: Sales_Rep: The name of the sales representative, Region: denoting the region they work in and Total_sales: Total Sales done by the sales representative.
I want to find only the sales reps with maximum sales in each region. The table has 50 rows.
I tried doing it using self join but no rows are returned.
The SQl code which I have written is:
SELECT s1.Sales_Rep, s1.Region,s1.Total_sales
FROM sales s1
JOIN sales s2
ON s1.Sales_Rep = s2.Sales_Rep
WHERE s1.Region = s2.Region
AND s1.Total_sales > s2.Total_sales
Can anyone please tell me how to solve this?The table image for reference

I used a CTE to get the max sales of each region then joined it back to the original table based on the total sales and region to find the saleperson
WITH MAX_CTE
AS
(
SELECT
REGION,
MAX(TOTAL_SALES) AS TOTAL_SALES
FROM SALES
GROUP BY REGION
)
SELECT
*
FROM SALES TABLE1
JOIN MAX_CTE CTE1 ON CTE1.REGION = TABLE1.REGION AND CTE1.TOTAL_SALES = TABLE1.TOTAL_SALES

Using a Where Statement with another Select statement, you'll be sure to get the highest total sales. By using distinct(Region) and Group by Region. The values will be seperated by Region so each will have its own Sales Rep with the highest Total sales.
Select Sales_Rep, Region, Total_sales
FROM sales
Where Total_sales = (Select max(Total_sales) from sales)
GROUP by Region;
Edited: The where statement should be stated before the group statement
Edited2 : Removed Distinct from Select statement

Related

Error Code: 1241. Operand should contain 1 column(s) when trying a subquery

I have created two table person with column id, name, mobile and another is transaction table with id, quantity, rate, total, pay, due, one person can have multiple entry in transaction table.
Now, I want to see the total quantity, total payment and total due against each name in person table.
I don't know much about sql, that's why I try for total quantity first but it give me error: "Error Code: 1241. Operand should contain 1 column(s)"
My sql is:
select id,name from person where(id) in
(select id, sum(quantity) from transaction group by id);
What can i do for, showing all field like: total quantity, total pay, total due.
You can use join
select id,name,total
from person p join
(select id, sum(quantity) as total from transaction group by id) as t on p.id=t.id
OR
select p.id,name,sum(quantity) as total from person p join transaction t
on p.id=t.id
group by p.id, name

Computed Column in Select Query?

I Want To Create A %Share Column Whose Values Are Derived By Dividing The Sale Of Each Customer With The Total Sale. I'm Using The Below Query But Get Error That Column 'Sale' Cannot Be Found. Is there Is A Way Through Which I Can Get Total Of Sale Column i.e. 600 ? Please Help ...
Select IsNull([Customer].[FirstName],'Total') as Customer,
format(Sum([MY_DB].[dbo].[Order].[TotalAmount]),'0.00') [Sale],
FORMAT(sum([MY_DB].[dbo].[Order].[TotalAmount])/ sum([Sale]),'0.00%') as 'Share%'
From Customer
INNER JOIN [MY_DB].[dbo].[Order]
ON [Customer].[Id]=[MY_DB].[dbo].[Order].[CustomerId]
Group By [Customer].[FirstName] with Rollup
Having (Sum([MY_DB].[dbo].[Order].[TotalAmount]) > (Select AVG([MY_DB].[dbo].[Order].[TotalAmount]) From [MY_DB].[dbo].[Order]))
Order By [Customer].[FirstName] Desc;
-
Desired Result:
Customer Sale %Share
Zbyszek 100 16.66 %
Yvonne 200 33.33 %
Yoshi 300 50.00 %
You have to modify the existing query quite a bit. I don't think you need with rollup.
For getting the total sales use sum() over(). Then divide each sale amount by the total to get the percentage. In the same way, using avg() over() you can compute the average and find customers with sales >= avgamount.
Select Customer,[Sale],[Share%]
from (
Select Distinct
c.[FirstName] as Customer,
format(sum(o.[TotalAmount]) over(partition by o.[CustomerId]),'0.00') as [Sale],
format(100.0*sum(o.[TotalAmount]) over(partition by o.[CustomerId]) / sum(o.[TotalAmount]) over(),'0.00%') as 'Share%',
AVG(o.[TotalAmount]) over() as 'AvgAmount'
From Customer c
INNER JOIN [MY_DB].[dbo].[Order] o ON c.[Id]=o.[CustomerId]
) t
Where Sale >= AvgAmount
Order By Customer Desc;
Without computing the average you can just check for customers with share >= 50%.
Select Customer,[Sale],[Share%]
from (
Select Distinct
c.[FirstName] as Customer,
format(sum(o.[TotalAmount]) over(partition by o.[CustomerId]),'0.00') as [Sale],
format(100.0*sum(o.[TotalAmount]) over(partition by o.[CustomerId]) / sum(o.[TotalAmount]) over(),'0.00%') as 'Share%'
From Customer c
INNER JOIN [MY_DB].[dbo].[Order] o ON c.[Id]=o.[CustomerId]
) t
Where [Share%] >= 50
Order By Customer Desc;
You can't define [Sale] column and use it in a function in the same SQL.
Easiest way to achieve this is just to surround your SQL with an outer SQL statement, where you'll also calculate the total sum and make the division.
(My syntax might not be MS-SQL exact, but this is to illustrate the idea)
Select [data].[FirstName],
format([data].[Sale],'0.00'),
format([data].[Sale] / [total].[totalSum],'0.00') FROM
(Select IsNull([Customer].[FirstName],'Total') as Customer,
Sum([MY_DB].[dbo].[Order].[TotalAmount] [Sale],
From Customer
INNER JOIN [MY_DB].[dbo].[Order]
ON [Customer].[Id]=[MY_DB].[dbo].[Order].[CustomerId]
Group By [Customer].[FirstName] with Rollup
Having (Sum([MY_DB].[dbo].[Order].[TotalAmount]) > (Select AVG([MY_DB].[dbo].[Order].[TotalAmount]) From [MY_DB].[dbo].[Order])) ) data,
(Select sum([MY_DB].[dbo].[Order].[TotalAmount] as [totalSum]) from [MY_DB].[dbo].[Order]) total
Order By [data].[FirstName] Desc;

How do I proceed on this query

I want to know if there's a way to display more than one column on an aggregate result but without it affecting the group by.
I need to display the name alongside an aggregate result, but I have no idea what I am missing here.
This is the data I'm working with:
It is the result of the following query:
select * from Salesman, Sale,Buyer
where Salesman.ID = Buyer.Salesman_ID and Buyer.ID = sale.Buyer_ID
I need to find the salesman that sold the most stuff (total price) for a specific year.
This is what I have so far:
select DATEPART(year,sale.sale_date)'year', Salesman.First_Name,sum(sale.price)
from Salesman, Sale,Buyer
where Salesman.ID = Buyer.Salesman_ID and Buyer.ID = sale.Buyer_ID
group by DATEPART(year,sale.sale_date),Salesman.First_Name
This returns me the total sales made by each salesman.
How do I continue from here to get the top salesman of each year?
Maybe the query I am doing is completely wrong and there is a better way?
Any advice would be helpful.
Thanks.
This should work for you:
select *
from(
select DATEPART(year,s.sale_date) as SalesYear -- Avoid reserved words for object names
,sm.First_Name
,sum(s.price) as TotalSales
,row_number() over (partition by DATEPART(year,s.sale_date) -- Rank the data within the same year as this data row.
order by sum(s.price) desc -- Order by the sum total of sales price, with the largest first (Descending). This means that rank 1 is the highest amount.
) as SalesRank -- Orders your salesmen by the total sales within each year, with 1 as the best.
from Buyer b
inner join Sale s
on(b.ID = s.Buyer_ID)
inner join Salesman sm
on(sm.ID = b.Salesman_ID)
group by DATEPART(year,s.sale_date)
,sm.First_Name
) a
where SalesRank = 1 -- This means you only get the top salesman for each year.
First, never use commas in the FROM clause. Always use explicit JOIN syntax.
The answer to your question is to use window functions. If there is a tie and you wand all values, then RANK() or DENSE_RANK(). If you always want exactly one -- even if there are ties -- then ROW_NUMBER().
select ss.*
from (select year(s.sale_date) as yyyy, sm.First_Name, sum(s.price) as total_price,
row_number() over (partition by year(s.sale_date)
order by sum(s.price) desc
) as seqnum
from Salesman sm join
Sale s
on sm.ID = s.Salesman_ID
group by year(s.sale_date), sm.First_Name
) ss
where seqnum = 1;
Note that the Buyers table is unnecessary for this query.

I can't get max and min from my table

How come this query returns an error?
select CUSTOMER, TOTAL_VALUE
from CUSTOMER, SALES
where TOTAL_VALUE in (select max(TOTAL_VALUE), min(TOTAL_VALUE)
from SALES)
When I just do max(TOTAL_VALUE) or min(TOTAL_VALUE) alone it works perfectly. But I need to get the min number in TOTAL_VALUE and max number in TOTAL_VALUE. Can anyone help me figure out why this query won't work for me? I would like to keep the structure that i have (using the in operator and nested subquery)
It returns an error because the subquery is returning two values, not one. Here is one fix:
select CUSTOMER, TOTAL_VALUE
from CUSTOMER cross join
SALES join
(select max(TOTAL_VALUE) as maxt, min(TOTAL_VALUE) as mint
from sales
) sm
where s.total_value in (sm.maxt, sm.mint);
That said, the query makes no sense. There you are going to get a list of every customer along with the value of the overall minimum and maximum sales.
This does answer your question. If you have another question, then provide sample data, desired results, in another question.
Try this (Joining SALES and CUSTOMER tables):
select C.CUSTOMER, MIN(TOTAL_VALUE), MAX(TOTAL_VALUE)
from SALES S
join CUSTOMER C on S.Customer_ID=C.Customer_ID
group by C.CUSTOMER
order by C.CUSTOMER

PostgreSQL: get the min of a column with it's associated city

I have been at this for the past two hours and have tried many different ways in regards to subquery and joins. Here's the exact question "Get the name and city of customers who live in the city where the least number of products are made"
Here is a snapshot of the database tables
I know how to get the min
select min(quantity)
from products
but this returns just the min without the city attached to it so I can't search for the city in the customers table.
I have also tried group by and found it gave me 3 min's (one for each group of cities) which i believe may help me
select city,min(quantity)
from products
group by city
Putting everything together I got something that looks like
SELECT
c.name,c.city
FROM
customers c
INNER JOIN
(
SELECT
city,
MIN(quantity) AS min_quantity
FROM
products
GROUP BY
city
) AS SQ ON
SQ.city = c.city
But this returns multiple customers, which isn't correct. I assume by looking at the database the city when the lowest number of products seems to be Newark and there are no customers who reside in Newark so I assume again this query would result in 0 hits.Thank you for your time.
Example
Here is an example "Get the pids of products ordered through any agent who makes at least one order for a customer in Kyoto"
and the answer I provided is
select pid
from orders
inner join agents
on orders.aid = agents.aid
inner join customers
on customers.cid = orders.cid
where customers.city = 'Kyoto'
In Postgresql you have sophisticated tools, viz., windowing and CTEs.
WITH
find_least_sumq AS
(SELECT city, RANK() OVER ( PARTITION BY city ORDER BY SUM(quantity) ) AS r
FROM products)
SELECT name, city
FROM customers NATURAL JOIN find_least_sumq /* ON city */
WHERE r=1; /* rank 1 is smallest summed quantity including ties */
In Drew's answer, you are zeronig in on the cities where the smallest number of any particular item is made. I interpret the question as wanting the sum of items made in that city.
I guess it be something around this idea:
select customers.name, city.city, city.min
from customers
join (
select city, sum (quantity) as min
from products
group by city
--filter by the cities where the total_quantity = min_quantity
having sum (quantity) = (
--get the minimum quantity
select min(quantity) from products
)
) city on customers.city = city.city
This can be made so much simpler. Just sort the output by the field you want to get the minimum of.
SELECT city, quantity FROM customers ORDER BY quantity LIMIT 1;
I have just figured out my own answer. I guess taking a break and coming back to it was all I needed. For future readers this answer will use a subquery to help you get the min of a column and compare a different column (of that same row) to a different tables column.
This example is getting the city where the least number of products are made (quantity column) in the products table and comparing that city to the cities to the city column in the customers table, then printing the names and the city of those customers. (to help clarify, use the link in the original question to look at the structure of the database I am talking about) First step is to sum all the products to their respective cities, and then take the min of that, and then find the customers in that city.Here was my solution
with citySum as(
select city,sum(quantity) as sum
from products
group by city)
select name,city
from customers
where city
in
(select city
from citySum
where sum =(
select min(sum)
from citySum))
Here is another solution I have found today that works as well using only Sub queries
select c.name,c.city
from customers c
where c.city
in
(select city
from
(select p.city,sum(p.quantity) as lowestSum
from products p
group by p.city) summedCityQuantities
order by lowestsum asc
limit 1)