Search code examples
c#sqlstored-procedureschartsasp.net-charts

MS Chart control - Optimize method for displaying 'zero' Y value columns for a Line chart type


I’m using Microsoft Chart extensions that ship with VS 2010. This suits my needs well, but I’ve run into an annoyance and am looking for a more elegant solution.

When charting a line graph, to achieve a continuous line, I require data for all X coordinates. My dataset is for number of sales by employee by month, where sales count is on the Y and month is on the X. The problem arises where no data is returned for an X value (ie. An employee took a month off)…so the line is not continuous.

I’m not sure if there is a setting I’ve overlooked in the Chart control, but my inelegant solution is to create ‘fake’ zero sales data for the months the employee posted no sales.

I’m using a stored procedure in MS SQL to create my dataset, where each column is a month and each row is for an employee. I create a new series in the Chart control for each employee then.

In order to capture my zero sales months, I have created a temp table in SQL.

CREATE TABLE @tblMonth (myMonth nvarchar(10), defaultCount int)
INSERT INTO @tblMonth VALUES (‘January’, 0)
…
INSERT INTO @tblMonth VALUES (‘December’, 0)

I then perform a join of my temp table on my actual data record and use

ISNULL (realData.Count, tblMonth.defaultCount) 

To get my ‘fake’ zero sales data.

This works…but FEELS really kludgy to me…I can’t help but feel I’ve overlooked something simple that would better suit my purposes. Again, I’ve got this working…but always looking for better ways of doing things and expand my knowledge base….so if anyone has suggestions of how better to accomplish the above, I’d love some suggestions or feedback.


Solution

  • If tblMonth.DefaultCount will always be zero, then why not:

    ISNULL (realData.Count, 0)
    

    Here's what I am guessing your query looks like:

    SELECT
      sales_month = DATENAME ( month, s.sale_date )
      , sales_month_n = DATEPART( month, s.sale_date)
      , salesperson = e.employee_name
      , numb_of_sales = COUNT ( 1 )
    
    FROM
     sales s
     JOIN employee e
       ON s.employee_id_salesperson = e.employee_id
    WHERE s.sale_date >= '1/1/2010' and s.sale_date < '1/1/2011'
    GROUP BY 
      DATENAME ( month, s.sale_date ), e.employee_name, DATEPART( month, s.sale_date)
    

    --which works fine, until you have an employee take off in June, July and August. You still want them to show up in the resultset, but with zero sales

    CREATE TABLE @tblMonth (myMonth nvarchar(10), n tinyint) 
        INSERT INTO @tblMonth VALUES ('January', 1) 
        ... 
        INSERT INTO @tblMonth VALUES ('December', 12)
    
    
    SELECT
        all_possibles.sales_month
        , all_possibles.salesperson
        , ISNULL ( actual.numb_of_sales, 0 )
    FROM 
        (
            SELECT
              sales_month = myMonth
              , sales_month_n = n
              , salesperson = e.employee_name
            FROM
                employee e
                ,@tblMonth M
        )all_possibles
        LEFT JOIN 
        (
            SELECT
              sales_month_n = DATEPART( month, s.sale_date)
              , salesperson = e.employee_name
              , numb_of_sales = COUNT ( 1 )
            FROM
             sales s
             JOIN employee e
               ON s.employee_id_salesperson = e.employee_id
            WHERE s.sale_date >= '1/1/2010' and s.sale_date < '1/1/2011'
            GROUP BY 
               e.employee_name, DATEPART( month, s.sale_date)
        )actuals
            ON 
            (
                all_possibles.salesperson = actuals.salesperson
                AND all_possibles.sales_month_n = actuals.sales_month_n
            )
    

    Sorry for the long winded answer. Hope you feel reassured that you are on the right track. Good luck!

    As to kludgy - instead of @tblMonth, I use permanent tables in a utility / resource database. it is already populated with things like a record for every minute in the day, or in this case, a record for every month in a year. These types of tables, forget what they are called - maybe a form of fact table? are VERY useful when looking for or filling in gaps in data.