Decile analysis - customer and revenue and vice versa - sql

I am trying to produce an analysis which shows 2 things.
Deciles (or percentiles) of customers and their revenue so I can see what 10% of customer count produce the the most revenue.
Deciles of Revenue : how many customers produce 10% of revenue.
select yeardate, decile, sum(revenue) as revenue, count(distinct(customername)) as cust_count
from
(
select yeardate,
customername,
ntile(10) over (order by sum(revenue) ) as decile,
sum(revenue) as revenue
from
(select
year(DateStamp) as yeardate ,
customername,
sum(Sell) as revenue
from MarginListView
where reporttype = 'Invoice' and sell >0 and year(datestamp) = 2018
group by year(DateStamp), customername) d
group by yeardate, CustomerName) c
group by yeardate, decile
order by 1,2
I can get the customer count deciles but not the revenue deciles....
using MS SQL server - Any help appreciated.

To get the number of customers that produce 10% of revenue, start with the cumulative revenue:
select customername, sum(sell) as revenue,
sum(sum(sell)) over (order by sum(sell) desc) as running_revenue
from MarginListView
where reporttype = 'Invoice' and sell > 0 and
year(datestamp) = 2018
group by customername;
To get the number that account for 10%:
select count(*)
from (select customername, sum(sell) as revenue,
sum(sum(sell)) over (order by sum(sell) desc) as running_revenue,
sum(sum(sell)) over () as total_revenue
from MarginListView
where reporttype = 'Invoice' and sell > 0 and
year(datestamp) = 2018
group by customername
) c
where running_revenue - revenue >= 0.1 * total_revenue;

Gordon - thanks for your help.... it really did get me towards where I needed to be.
I ended with this...
select
yeardate, customername,
sell,
cast((round(sum(sum(revenue_sub_tot)) over (order by sum(revenue_sub_tot) asc),2,2)) as decimal (2,2)) as revenue_percentiles,
cast((round(sum(sum(revenue_sub_tot)) over (order by sum(revenue_sub_tot) asc),1,1)) as decimal (2,2)) as revenue_deciles
from (select year(datestamp) as yeardate,
customername,
sum(sell) as sell,
sum(sell)/sum(sum(sell)) over () as revenue_sub_tot
from MarginListView
where reporttype = 'Invoice' and sell > 0
group by year(datestamp), customername
) c
group by yeardate, customername, sell
order by 1,3

Related

Querying revenue by percentile in googlesql

I'm trying to group companies and their revenues by percentiles (>90% as Top, 50-90% as middle, < 50% as bottom, in googlesql.
Table format for revenue_table:
|company | product | revenue |
------------------------------
I'm trying out doing a cross join to split these companies up:
SELECT
company,
SUM(revenue) as revenue,
CASE
WHEN SUM(revenue) > Percentile90_Max THEN "Top"
WHEN SUM(revenue) >= Percentile50_Max THEN "Middle"
ELSE "Bottom"
END as percentile_section,
Percentile50_Max,
Percentile90_Max,
FROM revenue_table
CROSS JOIN
(SELECT
APPROX_QUANTILES(revenue,100)[offset(50)] As Percentile50_Max,
APPROX_QUANTILES(revenue,100)[offset(90)] As Percentile90_Max
FROM
(SELECT
company,
SUM(revenue) as revenue
FROM revenue_table
GROUP BY 1
)
)
GROUP BY 1,4,5
Order by 2 desc
The code above currently works, but gets broken once I change my main select statement to:
SELECT
company,
--SUM(revenue) as revenue,
CASE
WHEN SUM(revenue) > Percentile90_Max THEN "Top"
WHEN SUM(revenue) >= Percentile50_Max THEN "Middle"
ELSE "Bottom"
END as percentile_section,
--Percentile50_Max,
--Percentile90_Max,
... same code here
GROUP BY 1
Ideally my end result should just be Company + percentile_section.
How should I do this without doing another subquery? Or is subquery really the only way to go in terms of querying efficiency?
Thank you!
You should be able to calculate the quantiles as part of the aggregation, so no subquery should be necessary:
SELECT company, SUM(revenue) as revenue,
(CASE WHEN SUM(revenue) > (APPROX_QUANTILES(SUM(revenue), 100) OVER ())[offset(90)] THEN 'Top'
WHEN SUM(revenue) >= (APPROX_QUANTILES(SUM(revenue), 100) OVER ())[offset(50)] THEN 'Middle'
ELSE 'Bottom'
END) as percentile_section
FROM revenue_table
GROUP BY 1
Order by 2 desc

SQL: Looking at Bundle of Products Sold

I have a sample DB below. I'm looking to see how many TV and Internet bundles we sold. In the sample data, only Bob and Trevor sold that bundle so we sold 2.
How do I write the query for the number of bundles sold by each Sales rep and the total price of the bundles sold?
Thanks
I imagine that, for a bundle to happen, the same sales person needs to have sold both products to the same customer.
I would approach this with two levels of aggregation. First group by sales person and customer in a subquery to identify the bundles, then, in an outer query, count how many such bundles happened for each sales person:
SELECT sales_person, COUNT(*) bundles_sold, SUM(total_price) total_price
FROM (
SELECT sales_person, customer_name, SUM(total_price) total_price
FROM mytable
WHERE product_name in ('TV', 'Phone')
GROUP BY sales_person
HAVING COUNT(DISTINCT product_name) = 2
) x
You can simply group the salesman's by counting the distinct products they sold -
SELECT Sales_Person, FLOOR(COUNT(DISTINCT product_name)/2) NO_OF_BUNDLES, sum(total_price)
FROM YOUR_TAB
WHERE product_name IN ('TV', 'Internet')
GROUP BY Sales_Person
HAVING COUNT(DISTINCT product_name) >= 2
Using cte as below:
with cte1(sales_person, customer_name, product_count) as
(
select sales_person, customer_name, count(product_name)
from sales
where product_name in ('TV', 'Internet')
group by sales_person, customer_name
having count(product_name) = 2
)
select sales_person, count(product_count)
from cte1
group by sales_person
I would suggest two levels of aggregation:
select sales_person, count(*), sum(total_price)
from (select sales_person, customer_name,
sum(total_price) as total_price,
max(case when product_name = 'tv' then 1 else 0 end) as has_tv,
max(case when product_name = 'phone' then 1 else 0 end) as has_phone,
max(case when product_name = 'internet' then 1 else 0 end) as has_internet
from t
group by sales_person, customer_name
) sc
where has_phone = 0 and
has_tv = 1 and
has_internet = 1
group by sales_person;
I recommend this structure because it is pretty easy to change the conditions in the where clause to return this for any bundle -- or even to aggregate by the three flags and return the totals for all bundles in one query.

SQL views, grouping by most sold items and customers who purchased most

This is my table:
Using this query, I am getting most sold items:
SELECT [Purchased Item], SUM([Overall Quantity purchased] )
FROM ReportDraft
GROUP BY [Purchased Item]
ORDER BY SUM([Overall Quantity purchased] )
This returns items and total quantity purchased by customer.
Can I somehow create a table like
ItemName | Total quantity purchased | Customer who purchased most | Customer quantity bought
Pie--------|---------11------------|---------------ALEX----------|--------3------------|
Thank you
I would use window functions and conditional aggregation:
SELECT [Purchased Item], sum(total) as total,
MAX(CASE WHEN seqnum = 1 THEN Customer END) as customer,
MAX(Total) as max_quantity
FROM (SELECT [Purchased Item], Customer, SUM([Overall Quantity purchased] ) as total,
ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY SUM([Overall Quantity purchased]) DESC) as seqnum
FROM ReportDraft
GROUP BY [Purchased Item], Customer
) rd
GROUP BY [Purchased Item]
ORDER BY SUM([Overall Quantity purchased] );

Microsoft SQL Server - Percentages of orders

I'm training on Northwind sample database and got task to do:
"Create query that returns: CompanyName, OrderID, SaleAmount (Value of that Order), Percentage value of that order, Total Value of Customers Orders.
I did it, everything works fine but now i want to add something else:
I want to add field that will show percentage share of individual order comaring it to total value of all orders - Sum(SaleAmount)
I did something like this:
SELECT
CompanyName,
OrderID,
SaleAmount,
CAST(100 * SaleAmount / SUM(SaleAmount) OVER (PARTITION BY CompanyName) AS decimal(5, 2)) AS 'Percent',
SUM(SaleAmount) OVER (PARTITION BY CompanyName) AS Total,
(SELECT
SUM(SaleAmount) AS Całość_Zamówienia
FROM dbo.[Sales Totals by Amount])
AS Suma_całkowita,
CAST(100 * SaleAmount / SUM(SaleAmount) OVER (PARTITION BY CompanyName) AS decimal(11, 2)) AS 'TEST'
FROM dbo.[Sales Totals by Amount]
GROUP BY CompanyName,
OrderID,
SaleAmount
But it shows stupid things, can you help me please? : )
Try this:
SELECT CompanyName, OrderID, SaleAmount,
CAST(100 * SaleAmount / SUM(SaleAmount) OVER(PARTITION BY CompanyName) as decimal(5,2)) as 'Percent',
SUM(SaleAmount) OVER(PARTITION BY CompanyName) as Total,
(SELECT Sum(SaleAmount) as Całość_Zamówienia FROM dbo.[Sales Totals by Amount]) as Suma_całkowita
,CAST(100 * SUM(SaleAmount) OVER(PARTITION BY CompanyName)/ (select sum(SaleAmount) from dbo.[Sales Totals by Amount]) as decimal(11,2)) as 'TEST'
FROM dbo.[Sales Totals by Amount]
GROUP BY CompanyName, OrderID, SaleAmount

How to sort by Total Sum calculated field in a Tablix

I have a Report in Microsoft Visual Studio 2010 that has a tablix. I have a list of Customers Sales grouped by Month. I would like to add a grand total of all the Months for each customer. I would then like to sort by descending amount of the grand total. I have added the grand total, but I can't figure out how to sort on it. Any suggestions?
Here is the initial dataset query:
SELECT
Customer, CustomerName, FiscalMonthNum, FiscalYear, SalesDlr
FROM
CustomerSalesDollars
WHERE
FiscalYear IN ('2013')
ORDER BY
SalesDlr DESC
with CSD as (
select Customer, CustomerName, FiscalMonthNum, FiscalYear, SalesDlr
from CustomerSalesDollars
WHERE FiscalYear in ('2013')
), YearlyTotals as (
select FiscalYear, Customer, CustomerName, SUM(SalesDlr) as YearlyTotal
from CSD
group by FiscalYear, Customer, CustomerName
)
select * from YearlyTotals
order by YearlyTotal desc
If you still want all the monthly breakdowns:
with CSD as (
select Customer, CustomerName, FiscalMonthNum, FiscalYear, SalesDlr
from CustomerSalesDollars
WHERE FiscalYear in ('2013')
), YearlyTotals as (
select FiscalYear, Customer, CustomerName, SUM(SalesDlr) as YearlyTotal
from CSD
group by FiscalYear, Customer, CustomerName
)
select CSD.*, YT.YearlyTotal from YearlyTotals YT
join CSD on CSD.FiscalYear = YT.FiscalYear
and CSD.Customer = YT.Customer
and CSD.CustomerName = YT.CustomerName
order by YearlyTotal desc, CSD.SalesDlr desc