Results 1 to 4 of 4

Thread: Select top N, Group by query

  1. #1
    Join Date
    May 2004
    Location
    Dunedin, New Zealand
    Posts
    33

    Select top N, Group by query

    Hi All,

    I am trying to return a result set that gives me the top 20 results for EACH group (PERILNAME in this case), not the top 20 results of the whole result set.

    I have been able to create the results I want using UNION, but this is not practical when there is more than a few groups. I think it should be possible using a derived table, but I am not sure how to do it! Below is the code the returns the results I am after, any ideas how to achieve this another way?

    SELECT TOP 20 LookupPeril.PERILNAME, accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, SUM(loccvg.VALUEAMT) AS [Total Value],
    COUNT(loc.LOCID) AS [Num Locs],loccvg.VALUECUR
    FROM loc
    INNER JOIN loccvg ON loc.LOCID = loccvg.LOCID
    INNER JOIN accgrp ON loc.ACCGRPID = accgrp.ACCGRPID
    INNER JOIN RMS_Reports.dbo.LookupPeril LookupPeril ON loccvg.PERIL = LookupPeril.PERILCODE
    WHERE LookupPeril.PERILNAME = 'Earthquake'
    GROUP BY accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, LookupPeril.PERILNAME, loccvg.VALUECUR
    UNION
    SELECT TOP 20 LookupPeril.PERILNAME, accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, SUM(loccvg.VALUEAMT),
    COUNT(loc.LOCID) ,loccvg.VALUECUR
    FROM loc
    INNER JOIN loccvg ON loc.LOCID = loccvg.LOCID
    INNER JOIN accgrp ON loc.ACCGRPID = accgrp.ACCGRPID
    INNER JOIN RMS_Reports.dbo.LookupPeril LookupPeril ON loccvg.PERIL = LookupPeril.PERILCODE
    WHERE LookupPeril.PERILNAME = 'Windstorm'
    GROUP BY accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, LookupPeril.PERILNAME, loccvg.VALUECUR
    UNION
    SELECT TOP 20 LookupPeril.PERILNAME, accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, SUM(loccvg.VALUEAMT),
    COUNT(loc.LOCID) ,loccvg.VALUECUR
    FROM loc
    INNER JOIN loccvg ON loc.LOCID = loccvg.LOCID
    INNER JOIN accgrp ON loc.ACCGRPID = accgrp.ACCGRPID
    INNER JOIN RMS_Reports.dbo.LookupPeril LookupPeril ON loccvg.PERIL = LookupPeril.PERILCODE
    WHERE LookupPeril.PERILNAME = 'Tornado/Hail'
    GROUP BY accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, LookupPeril.PERILNAME, loccvg.VALUECUR
    UNION
    SELECT TOP 20 LookupPeril.PERILNAME, accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, SUM(loccvg.VALUEAMT),
    COUNT(loc.LOCID) ,loccvg.VALUECUR
    FROM loc
    INNER JOIN loccvg ON loc.LOCID = loccvg.LOCID
    INNER JOIN accgrp ON loc.ACCGRPID = accgrp.ACCGRPID
    INNER JOIN RMS_Reports.dbo.LookupPeril LookupPeril ON loccvg.PERIL = LookupPeril.PERILCODE
    WHERE LookupPeril.PERILNAME = 'Flood'
    GROUP BY accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, LookupPeril.PERILNAME, loccvg.VALUECUR
    ORDER BY LookupPeril.PERILNAME, [Total Value]

    TIA.

  2. #2
    Join Date
    Feb 2003
    Posts
    1,048
    Use a cursor to loop through each group. Insert each recordset into a temp table or table variable and then select that at the end.

  3. #3
    Join Date
    May 2004
    Location
    Dunedin, New Zealand
    Posts
    33
    Thanks Rawhide, had a feeling that would be mentioned as the solution!

    Unfortunately a cursor is not really on option, the query is for a Reporting Services report, 1 of about 20 queries for different datasets within the report so the report would just take too long to run.

    Is there any other possible solutions?

    Cheers.

  4. #4
    Join Date
    May 2004
    Location
    Dunedin, New Zealand
    Posts
    33
    Below is a solution to this problem from zlp321002 that worked.

    Below is the code I used for anyone else needing to do this (Added Union to sum all values not in the top 20 as well)


    SELECT LookupPeril.PERILNAME, accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, SUM(loccvg.VALUEAMT) AS [Total Value],
    COUNT(loc.LOCID) AS [Num Locs],loccvg.VALUECUR
    INTO #TOPTEMP
    FROM loc
    INNER JOIN loccvg ON loc.LOCID = loccvg.LOCID
    INNER JOIN accgrp ON loc.ACCGRPID = accgrp.ACCGRPID
    INNER JOIN RMS_Reports.dbo.LookupPeril LookupPeril ON loccvg.PERIL = LookupPeril.PERILCODE
    GROUP BY accgrp.ACCGRPNUM, accgrp.ACCGRPNAME, LookupPeril.PERILNAME, loccvg.VALUECUR


    select
    t.PERILNAME,t.ACCGRPNUM,t.ACCGRPNAME,t.[Total Value],t.[Num Locs],t.VALUECUR
    from
    #TOPTEMP t
    where
    t.ACCGRPNUM in (select top 20 ACCGRPNUM from #TOPTEMP x where x.PERILNAME = t.PERILNAME)
    Union
    select PERILNAME, 'TOTAL', 'OTHER', SUM([Total Value]), SUM([Num Locs]), VALUECUR from #TOPTEMP
    Where ACCGRPNUM not in (
    select
    t.ACCGRPNUM
    from
    #TOPTEMP t
    where
    t.ACCGRPNUM in (select top 20 ACCGRPNUM from #TOPTEMP x where x.PERILNAME = t.PERILNAME))
    Group by PERILNAME, VALUECUR
    order by 1,4 desc

    Cheers.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •