Search code examples
sqlsql-server-2008t-sqlsummary

Generate summary data based on configuration table in SQL Server


I'm trying to generate a summary from a list of scores in SQL Server 2008.
I have two tables: SQL Fiddle link

The ScorePerson table contains people's ID and their score from -5 to 15. End users of my SQL/Stored Procedure needs to create a summary like this:

Scoreband| TotalNoOfPeople | AvgScore
--------------------------------
-5 to 0  | 2               | -2
0 to 5   | 3               |  2
5 to 10  | 2               |  8
10 to 15 | 3               | 13.3

The score band i.e. the min and max values should be configurable from the ScoreMinMax table by the end user.

I have tried to achive this using CASE stement, but it generates the summary as columns. I I would probably need to pivot it or use UNION from multiple select statements. But this approach doesn't seem scalable if there were new rows added to the ScoreMinMax table. So far I was able to achieve some results similar to the example above using CROSS JOINT, but it doesn't always produces the correct results.

Is anyone able to point me in the right direction on how to achieve this please?

SQL Fiddle link

ScorePerson - contains actual scores

Table screenshot

ScoreMinMax - the configuration for min and max score bands

enter image description here


Solution

  • You can use aggregate functions:

    select title ScoreBand,
      count(*) TotalNoPeople, 
      avg(p.score) AvgScore  
    from scoreperson p
    inner join scoreminmax m
      on p.score between m.minscore and m.maxscore
    group by Title
    order by cast(left(title, 2) as int) 
    

    see SQL Fiddle with Demo

    If you have no person in an existing range, you can us something like this:

    select case when title is not null 
                then title
                else 'No Range' end ScoreBand,
      count(personid) TotalNoPeople, 
      avg(p.score) AvgScore  
    from scoreperson p
    left join scoreminmax m
      on p.score between m.minscore and m.maxscore
    group by id, Title
    order by id
    

    see SQL Fiddle with Demo

    edit #2, based on your comments you can use:

    select m.title ScoreBand,
      count(p.personid) TotalNoPeople, 
      avg(p.score) AvgScore  
    from scoreminmax m
    left join scoreperson p
      on p.score between m.minscore and m.maxscore
    group by m.id, m.Title
    order by m.id;
    

    see SQL Fiddle with Demo