I'm running on a 2012 MS-SQL server and have a table USER with Age, Gender among other fields and a SALES table with sales records.
I'm currently calculating the Sales Leaderboard showing an list of Sales People ordered by their TOP Sales so to give an example this list returns various sales rep based on their Top Sales. Somewhere in the middle of the list we have Mr. Thomas which let's say is #4th.
My current task is to display how Thomas compares to sales reps that have the same Age as him and also how he compares with sales rep that have the same gender as him. The calculation will return a different result than the overall list described above.
My ideal stored procedure would receive 1 param (UserId) and return the following single record values: OverallPosition, OverallPositionTotalCount, AgePosition, AgeTotalCount, GenderPosition, GenderTotalCount
DATA SAMPLE:
CREATE TABLE dbo.User
(
UserId int NOT NULL IDENTITY (1, 1),
Name nvarchar(50) NOT NULL,
Age int NULL,
Gender nvarchar(10) NULL
)
1, James, 30, 'male'
2, Monica, 27, 'female'
3, Paul, 30, 'male'
4, Thomas, 30, 'male'
5, Mike, 22, 'male'
6, Sabrina, 30, 'female'
CREATE TABLE dbo.Sales
(
SalesId int NOT NULL IDENTITY (1, 1),
UserId int NOT NULL,
TotalSale int NOT NULL
) ON [PRIMARY]
1, 1, $900,000
2, 1, $1,000,000
3, 2, $900,000
4, 2, $400,000
5, 3, $750,000
6, 3, $300,000
7, 4, $875,000
8, 5, $700,000
9, 5, $1,200,000
10, 6, $850,000
Sales Leaderboard list
SELECT u.UserId, u.Name, MAX(s.TotalSale) as TopSale, Count(*) OVER () AS TotalCount
FROM User u
INNER JOIN Sales s on s.UserId = u.UserId
GROUP BY u.UserID, u.Name
ORDER BY TopSale DESC
OFFSET (@PageIndexSelected) * @PageCountSelected ROWS
FETCH NEXT @PageCountSelected ROWS ONLY
Ideal Calculation Results
Since Thomas (userId 4) is 30 of Age and 'male', his Stats should look like this
OverallPosition = 4; OverallPositionTotalCount = 6 (i.e 4 out of 6)
$1,200,000 Mike
$1,000,000 James
$900,000 Monica
$875,000 Thomas
$850,000 Sabrina
$750,000 Paul
AgePosition = 2; AgeTotalCount = 4 (i.e. 2 out of 4)
$1,000,000 James
$875,000 Thomas
$850,000 Sabrina
$750,000 Paul
GenderPosition = 3; GenderTotalCount = 4 (i.e 3 out of 4)
$1,200,000 Mike
$1,000,000 James
$875,000 Thomas
$750,000 Paul
Note
The expected result is ONLY the values for OverallPosition, OverallPositionTotalCount, AgePosition, AgeTotalCount, GenderPosition, GenderTotalCount for a single user (the stored procedure will receive the UserId as param) and NOT the actual list.
EXPECTED RETURN
OverallPosition = 4,
OverallPositionTotalCount = 6,
AgePosition = 2,
AgeTotalCount = 4,
GenderPosition = 3,
GenderTotalCount = 4
As I stated on my comments, I really don't know how to approach this problem. I hope that somebody will be willing to help !!
The first CTE gets the max sales for each person. The second uses the windowing functions rank()
and count()
with an appropriate over()
clause to calculate the position and totals.
with C1 as
(
select U.UserId,
U.Gender,
U.Age,
max(S.TotalSale) as TotalSale
from dbo.[User] as U
inner join dbo.Sales as S
on U.UserId = S.UserId
group by U.UserId,
U.Gender,
U.Age
), C2 as
(
select C1.UserId,
C1.TotalSale,
rank() over(order by C1.TotalSale desc) as OverallPosition,
rank() over(partition by C1.Age order by C1.TotalSale desc) as AgePosition,
rank() over(partition by C1.Gender order by C1.TotalSale desc) as GenderPosition,
count(*) over() as OverallPositionTotalCount,
count(*) over(partition by C1.Age) as AgeTotalCount,
count(*) over(partition by C1.Gender) as GenderTotalCount
from C1
)
select C2.OverallPosition,
C2.OverallPositionTotalCount,
C2.AgePosition,
C2.AgeTotalCount,
C2.GenderPosition,
C2.GenderTotalCount
from C2
where C2.UserId = 4;
SQL Fiddle
Alternative:
select C.OverallPosition,
C.OverallPositionTotalCount,
C.AgePosition,
C.AgeTotalCount,
C.GenderPosition,
C.GenderTotalCount
from (
select U.UserId,
S.TotalSale,
rank() over(order by S.TotalSale desc) as OverallPosition,
rank() over(partition by U.Age order by S.TotalSale desc) as AgePosition,
rank() over(partition by U.Gender order by S.TotalSale desc) as GenderPosition,
count(*) over() as OverallPositionTotalCount,
count(*) over(partition by U.Age) as AgeTotalCount,
count(*) over(partition by U.Gender) as GenderTotalCount
from dbo.[User] as U
cross apply (
select max(S.TotalSale) as TotalSale
from dbo.Sales as S
where U.UserId = S.UserId
) as S
) as C
where C.UserId = 4;
SQL Fiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With