开发者

Reporting on data when data is missing (ie. how to report zero activities for a customer on a given week)

I want to create a report which aggregates the number of activities per customer per week. If there has been no activites on that custom开发者_开发百科er for a given week, 0 should be displayed (i.e week 3 and 4 in the sample below)

CUSTOMER | #ACTIVITIES | WEEKNUMBER

A | 4 | 1

A | 2 | 2

A | 0 | 3

A | 0 | 4

A | 1 | 5

B ...

C ...

The problem is that if there are no activities there is no data to report on and therefor week 3 and 4 in the sample below is not in the report.

What is the "best" way to solve this?


Try this:

DECLARE @YourTable table (CUSTOMER char(1), ACTIVITIES int, WEEKNUMBER int)
INSERT @YourTable VALUES ('A' , 4 , 1)
INSERT @YourTable VALUES ('A' , 2 , 2)
INSERT @YourTable VALUES ('A' , 0 , 3)
INSERT @YourTable VALUES ('A' , 0 , 4)
INSERT @YourTable VALUES ('A' , 1 , 5)
INSERT @YourTable VALUES ('B' , 5 , 3)
INSERT @YourTable VALUES ('C' , 2 , 4)


DECLARE @StartNumber int
       ,@EndNumber   int
SELECT @StartNumber=1
      ,@EndNumber=5

;WITH AllNumbers AS
(
    SELECT @StartNumber AS Number
    UNION ALL
    SELECT Number+1
        FROM AllNumbers
        WHERE Number<@EndNumber
)
, AllCustomers AS
(
    SELECT DISTINCT CUSTOMER FROM @YourTable
)
SELECT
    n.Number AS WEEKNUMBER, c.CUSTOMER, CASE WHEN y.Customer IS NULL THEN 0 ELSE y.ACTIVITIES END AS ACTIVITIES
    FROM AllNumbers                   n
        CROSS JOIN AllCustomers       c
        LEFT OUTER JOIN @YourTable    y ON n.Number=y.WEEKNUMBER AND c.CUSTOMER=y.CUSTOMER

--OPTION (MAXRECURSION 500)

OUTPUT:

WEEKNUMBER  CUSTOMER ACTIVITIES
----------- -------- -----------
1           A        4
1           B        0
1           C        0
2           A        2
2           B        0
2           C        0
3           A        0
3           B        5
3           C        0
4           A        0
4           B        0
4           C        2
5           A        1
5           B        0
5           C        0

(15 row(s) affected)

I use a CTE to build a Numbers table, but you could build a permanent one look at this question: What is the best way to create and populate a numbers table?. You could Write the Query without a CTE (same results as above):

SELECT
    n.Number AS WEEKNUMBER, c.CUSTOMER, CASE WHEN y.Customer IS NULL THEN 0 ELSE y.ACTIVITIES END AS ACTIVITIES
    FROM Numbers n
        CROSS JOIN (SELECT DISTINCT 
                        CUSTOMER 
                        FROM @YourTable
                   ) c
        LEFT OUTER JOIN @YourTable y ON n.Number=y.WEEKNUMBER AND c.CUSTOMER=y.CUSTOMER
    WHERE n.Number>=1 AND n.Number<=5
    ORDER BY n.Number,c.CUSTOMER


Keep a table of time periods separately, and then outer left join the activities to it.

Like:

select *
from ReportingPeriod as p
left join Activities as a on a.ReportingPeriodId = p.ReportingPeriodId;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜