views:

94

answers:

1

I currently use SQL2008 where I have a stored procedure that fetches data from a table that then gets fed in to a line graph on the client. This procedure takes a from date and a too date as parameters to filter the data. This works fine for small datasets but the graph gets a bit muddled when a large date range is entered causes thousends of results.

What I'd like to do is provide a max amount of records to be returned and return records at evenly spaced intervals to give that amount. For example say I limited it to 10 records and the result set was 100 records I'd like the stored procedure to return every 10th record.

Is this possible wihtout suffering big performance issues and what would be the best way to achieve it? I'm struggling to find a way to do it without cursors and if thats the case I'd rather not do it at all.

Thanks

+2  A: 

Assuming you use at least SQL2005, you could do somesting like

WITH p as (
     SELECT a, b,
            row_number() OVER(ORDER BY time_column) as row_no,
            count() OVER() as total_count
       FROM myTable
      WHERE <date is in range>
     )
SELECT a, b
  FROM p
 WHERE row_no % (total_cnt / 10) = 1

The where condition in the bottom calculates the modulus of the row number by the total number of records divided by the required number of final records.

If you want to use the average instead of one specific value, you would extend this as follows:

WITH p as (
     SELECT a, b,
            row_number() OVER(ORDER BY time_column) as row_no,
            count() OVER() as total_count
       FROM myTable
      WHERE <date is in range>
     ),
    a as (
    SELECT a, b, row_no, total_count,
           avg(a) OVER(partition by row_no / (total_cnt / 10)) as avg_a
      FROM p
    )
SELECT a, b, avg_a
  FROM a
 WHERE row_no % (total_cnt / 10) = 1

The formula to select one of the values in the final WHERE clause is used with the % replaced by / in the partition by clause.

Frank
Wicked completely forgot about row_number thanks
Gavin Draper
I just realized that I forgot parentheses, I will add them to my answer.
Frank
This can easily be adapted to average instead of filtered.
Emtucifor
What would be the best way to adapt this for averages? Is it to use a sub query so each returned row works out its own average?
Gavin Draper
@Gavin I edited my answer to show how the average could be used. The main issue to take into account is that division of integers results in an integer with the fractional part cut off. This can be used to create partitions in the OVER().
Frank
Brilliant. Thanks
Gavin Draper