Reputation: 175
Based on the answer to a previous question of mine. I end up with a result set something like:
PartyName Risk SubTotal Total
A High 100 280
B Med 25 45
A Low 30 280
A Med 70 280
B Low 10 45
C High 110 170
C Med 60 170
D Low 30 30
A Med 80 280
B Low 10 45
What I need is to SELECT TOP N unique PartyName with highest Amounts, i.e if N = 2 the result should be:
PartyName Risk SubTotal Total
A High 100 280
A Low 30 280
A Med 70 280
C High 110 170
C Med 60 170
A Med 80 280
all entries with the highest N Total
values.
Tried this:
SELECT DISTINCT TOP(10) s.PartyName, s.Risk, s.SubTotal, s2.Total
FROM
(SELECT PartyName, Risk, SUM(CAST(Amount AS DECIMAL)) SubTotal
FROM CustomerData
GROUP BY PartyName, Risk) S
LEFT JOIN
(SELECT PartyName, SUM(CAST(Amount AS DECIMAL)) Total
FROM CustomerData
GROUP BY PartyName) S2
ON S.PartyName = S2.Partyname
But doesn't work
Upvotes: 1
Views: 999
Reputation: 1269643
I think this version should do what you want:
SELECT TOP (10) WITH TIES PartyName, Risk,
SUM(CAST(Amount AS DECIMAL)) as SubTotal,
MAX(SUM(CAST(Amount AS DECIMAL))) OVER (PARTITION BY PartyName) as Total
FROM CustomerData
GROUP BY PartyName, Risk
ORDER BY Total DESC, PartyName;
EDIT:
The above gives all rows tied with the 10th. If you want all rows with the 10 distinct values, then let's use DENSE_RANK()
:
SELECT cd.*
FROM (SELECT cd.*, DENSE_RANK() OVER (ORDER BY Total DESC) as seqnum
FROM (SELECT TOP (10) WITH TIES PartyName, Risk,
SUM(CAST(Amount AS DECIMAL)) as SubTotal,
MAX(SUM(CAST(Amount AS DECIMAL))) OVER (PARTITION BY PartyName) as Total
FROM CustomerData
GROUP BY PartyName, Risk
) cd
) cd
WHERE seqnum <= 10
ORDER BY Total DESC, PartyName;
Upvotes: 0
Reputation: 873
Off the top off my head, maybe something like this:
if object_id('tempdb.dbo.#test') is not null drop table #test
create table #test
(
partyname varchar(50),
Risk varchar(50),
amount int
)
insert into #test
select 'A','High',50
union all select 'B','Med', 15
union all select 'A','Low', 12
union all select 'A','Med' , 43
union all select 'B','Low' , 65
union all select 'C','High', 12
union all select 'C','Med' , 789
union all select 'D','Low' , 12
union all select 'A' ,'Med', 34
union all select 'B' ,'Low', 43
SELECT
main.PartyName,
main.Risk,
main.SubTotal,
TotalValues.Total
FROM
--get party+risk+subtotal
(
SELECT PartyName, Risk, SUM(CAST(Amount AS DECIMAL)) SubTotal
FROM #test
GROUP BY PartyName, Risk
) main
--get total by partyname with a rownum to get top N, where N=2
INNER JOIN
(SELECT
b.partyName, b.Total, row_number() over (order by Total desc) as rid
FROM
(
SELECT b.PartyName, SUM(CAST(Amount AS DECIMAL)) as Total
FROM #test b
group by b.PartyName
) as b
) as TotalValues
on TotalValues.partyName = main.partyName
and TotalValues.rid <= 2 --n = 2
order by
main.partyname,
TotalValues.Total
Upvotes: 1
Reputation: 35323
1st we get a set of data with the totals, next we find the range of totals of interest, finally we get teh results...
Untested:
WITH mAgg AS (SELECT partyName
, Risk
, sum(cast(amount as decimal(10,2)) over (partition by partyName, Risk) as subTotal
, sum(cast(amount as decimal(10,2)) over (partition by partyName) as Total
FROM CustomerData),
mRange as (SELECT distinct top 2 total from mAgg order by total desc)
SELECT * FROM mAgg where Total >= (SELECT min(total)
FROM mRange))
Or maybe we could just dense_rank() over (partition by total desc) and then get the anything with rank >=2 or N...
Upvotes: 0