Problem
Our business users want to report on some fact data aggregated by week. They define a week as beginning on Sunday and ending on Saturday without regard to the year. An example query would be how many employees were hired in each of the previous four weeks? While SQL Server has the DATEPART function which has an option to give the week number in the year for any given date, the week number resets to 1 when the year changes. Can your think of an easy way to implement this type of functionality where we can determine a week number then simply add or subtract a number of weeks to come up with our range of weeks?
Solution
There are probably a number of possible solutions but the one that comes to mind is to add a cumulative week number column to the date dimension. This column will be assigned a sequential number representing the week; i.e. every day in a Sunday through Saturday range is assigned the same number then increment the number on each Sunday. We will also create a function that will return the week number for any given date. After determining the week number of a particular date, we can use a simple BETWEEN in our WHERE clause to filter the date dimension on a range of weeks and join to the relevant fact table.
Let’s walk through the steps to implement the Cumulative Week column.
1. Create a simple date dimension: |
CREATE TABLE dbo.dim_Date ( |
2. Populate the date dimension with a range of dates: |
DECLARE @StartDate DATETIME |
Now let’s add the CumulativeWeek column to the date dimension and populate it. We want to assign the value 1 to the first week in the date dimension then increment from there. Remember the week begins on Sunday. We get the date of the first Sunday in the date dimension, use a common table expression to calculate the number of days between each date and the first Sunday, then assign the week number by dividing the number of days by 7 and adding 1.
3. Add CumulativeWeek column to the date dimension: |
ALTER TABLE dbo.dim_Date |
4. Populate the CumulativeWeek column in the date dimension: |
DECLARE @Week1Date DATETIME |
Our next task is to create a function that will return the CumulativeWeek for any given date. The function accepts a DATETIME parameter, truncates the time portion, joins to the date dimension to retrieve the CumulativeWeek, then returns the week.
5. Create function to return the CumulativeWeek for a date: |
CREATE FUNCTION dbo.udf_GetCumulativeWeekForDate( |
6. Test the function with some sample dates: |
SELECT |
To complete our example, assume that we want to determine how many employees have been hired in each of the previous four weeks. We’ll create a simple fact table that has the hire date which is an integer that joins to the date dimension. We’ll populate the fact table with some sample data and create our query. We get the CumulativeWeek of the current date (assume January 22, 2008), then set our CumulativeWeek range to between CumulativeWeek – 4 and CumulativeWeek – 1.
7. Create employee activity fact table: |
CREATE TABLE dbo.fact_EmployeeActivity ( |
8. Populate the employee activity fact table: |
INSERT INTO dbo.fact_EmployeeActivity(fk_HireDate) |
9. Query employees hired in the last 4 weeks: |
DECLARE @BeginWeek INTEGER |
10. Query results: |
Next Steps
- Try out the sample code and refer back to this tip if you have a date dimension requirement to handle periods that span a year.
- Remember that a successful data warehousing project has to make querying easy for ordinary business users who use reporting tools (not straight T-SQL). So coming up with a simple way to filter queries is a big plus.
- There are many groupings based on dates; take a look at the DATEPART and DATENAME functions in SQL Server Books Online to get some ideas for other values that would be useful in your date dimension.