SQL (DB2) query to get count of top 10% revenue contributing customers - sql

I work for a telecom company and I need to run a scheme for top valued customers who contributed 10% of total company's revenue in the month. I want to know the count of customers who are eligible for this scheme? I am using SQL DB2.
Ex - In the below table, Sum of the Revenue is 5000 and its 10% is 500, and I want to know the count of minimum number of customers whose sum of revenue would be either 500 or just above 500
Customers Revenue
A 156
B 259
C 389
D 125
E 578
F 321

To find all customers where their total revenue is at least 10 percent of the overall revenue:
select customer
from the_table
group by customer
having sum(revenue) >= (select sum(revenue) * 0.1 from the_table);
Your sample data doesn't show this, but this also deals with multiple rows per each customer in the table (your example only has a single row per customer)
The get the count of that:
select count(*)
from (
select customer
from the_table
group by customer
having sum(revenue) >= (select sum(revenue) * 0.1 from the_table)
) t

I interpret the question as wanting the highest revenue customers whose sum is at least 10% of the total revenue.
You need a cumulative sum for this:
select count(*)
from (select t.*, sum(revenue) over (order by revenue desc) as cume_rev,
sum(revenue) over () as tot_rev
from t
) t
where cume_rev <= tot_rev * 0.1;
This assumes that there is one row per customer.
EDIT:
For "just above", the where clause should be:
where cume_rev - revenue < tot_rev * 0.1;

Related

How to get the top performing employees from each Region?

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

How to summing up the row values by passing condition

I want to sum up the column (price) by passing sum limitation.
For example I have the below table and I want to limit the records by 10k or 15k.
ID PRICE
x1 10,000
x2 20,000
x3 5,000
x4 7,500.00
I want the result should be
For <=10000
ID PRICE
x1 10,000
<=15000
ID PRICE
x1 10,000
x3 5,000
<=14000
ID PRICE
x3 5,000
x4 7,500.00
I made some search on it.I find some window functions in postgresql i.e OVER function. so I written the below query
WITH cte AS (
SELECT *, sum(price) OVER (order BY id) AS total
FROM test1
)
SELECT *
FROM cte
WHERE total <= amount
But condition <=15,000 and <=14000 not bringing the right result.
I want to sum up the price column and fetch the records which matches the sum result with our given amount or condition and more specifically it should return the records by verifying and returning any other record can accommodate within the amount which we pass
Please help me for it.
Thanks
your Q is not clear but if you want you can sort the price column so you can get the minimum sum that is <= the limit.
try order by on price col:
WITH cte AS (
SELECT *, sum(price) OVER (order BY price) AS total
FROM test1
)
SELECT *
FROM cte
WHERE total <= amount
Play here https://www.db-fiddle.com/f/mckDPhtrY4vRrkF2NjhQcC/0
WITH b AS (
SELECT *, sum(price) OVER (order BY price) AS total
FROM a
)
SELECT *
FROM b
WHERE (total <= your_max OR price <= your_max) AND total >= your_min

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;

Find the areaid that sells most number of products but with less discount

I am pretty new to SQL Server.
I have a question on one of the queries that I am trying to come up with
I have a table like this:
pid areaid units discount
-------------------------
1 1 10 10%
2 1 20 10%
3 2 30 5%
4 2 40 15%
5 1 50 10%
6 3 10 0%
I am trying to find the areaid that sells most number of products(units) but with less discount.
I tried some query as below but I couldn't figure out a way to join the below 2 queries.
I was able to find the least discount using the below query
select
min(y.discount)
from
(select
sum(discount) as discount
from
productinfo
group by
areaid) y
but not sure how to get the area id corresponding to that aggregated discount.
Similarly I figured out a query to return maximum number of products aggregated by areaid
select
max(y.uomsum)
from
(select
sum(uom) as uomsum
from
productinfo
group by
areaid) y
It would be great if anyone can help me with this query.
select areaid, MAX(TotalUnits), MIN(TotalDiscount)
FROM
(
select areaid , SUM(units) as TotalUnits, SUM(discount) TotalDiscount
from Table1
group by areaid
)T
group by areaid
May be something like this
SELECT MIN(Y.Discount),MAX(Y.Units)
FROM
(SELECT AreaID,SUM(Discount) AS Discount ,SUM(units) as Units
FROM productinfo
GROUP BY Areaid
) Y
It seems to me, that you need to calculate the average discount per area discount, then sum.
Select
sum(discountedUnits), areaid
from (
select
sum(units) as units,
sum(units) * (1-(convert(float, discount)/100)) as discountedUnits,
convert(float, sum(units) * (1-(convert(float, discount)/100))) / sum(units) as averageUnit,
areaid,
discount
from
productinfo
group by areaid, discount) as g
group by areaid
Here's a fiddle
To get the max, you could do a top 1 and order by descending, or put it all in another subselect

Percentage of the total revenue

I have category, Sub-category and Revenue.
Category Sub-Category Revenue Percentage
---------------------------------------------------------
Books Text Books 5000 (5000/14000)*100
Comics Books 6000
Horror Books 3000
Now my question is, how to achieve like this using SQL?
I need percentage wrt to total sales for that category.
Oracle has RATIO_TO_REPORT analytic function, which computes the ratio of a value to the sum of a set of values.
select category, subcategory, revenue,
round((ratio_to_report(revenue) over (partition by category) * 100),2) as percentage
from mytable;
Output:
CATEGORY SUBCATEGORY REVENUE PERCENTAGE
-----------------------------------------
books text 5000 35.71
books horror 3000 21.43
books comics 6000 42.86
Sample fiddle here
You can use an analytical SUM function:
select
Category,
SubCategory,
Revenue,
Revenue * 100 / sum(Revenue) over (partition by Category) as Percentage
from
yourTable
;
You can use a subselect to get the overall revenue and use it in the calculations.
SELECT category, sub-category, revenue,
((revenue /
SELECT sum(inne.revenue)
FROM table inne
WHERE inne.category = oute.category) * 100) AS percentage
FROM table oute