Duration Dimension
For measuring short durations, such as telephone calls or handling times.
Q1 Linear Grain?
The question I haven’t answered is whether the dimension should be at the finest grain for all durations. The grain I am using is seconds but probably after 30 minutes that’s finer than is needed. That’s 86,400 rows for a day. An alternative would be using a log (ish) scale for DimDurationKey: seconds up to 1 hour; minutes up to 24 hours, hours up to ? 7 days, then days… weeks… months. This would allow a single Duration Dimension to cover a wide range of periods without becoming huge. DimDimensionKey would have to be calculated during load.
Q2 Range Titles
What is a clear way of creating range titles: 0-1 minutes, 1-5 minutes, etc. Strictly these are 0-59 secs, 1min – 1:59, 2min – 4:59, although users probably think of them as 1min, 2min, 5min.
- 0:00 – 0:59
- 1:00 – 1:59
- 2:00 – 4:59
- 5:00 – 59:59
Or
- 0 – 59 secs
- 1 min – 1:59
- 2 min – 4:59
- 5 min – 59:59
Neither of those is clear or elegant. The second emphasises the start of each range whereas the information is that it’s in the “5 minute” band, whereas “2 min – 4:59” most salient value is “2 min”.
Based on this I looked at rounding the end of each range.
- 0 – 60 secs
- 1:01- 2 min
- 2:01 – 5 min
- 5:01 – 1 hour
That looks better but it gets complicated once you move beyond 1 hour. How to express the next segment up to say 1.5 hours:
- 1:00:01 to 1 hour 3o mins
- 1:00:01 to 1:30:00
- 1:00:01 to 1 and a half hours
All are ugly mixes of units.
I think for short durations I am resigned to accept the one-second inaccuracy of “0-1 minute”, “2-5 minutes” for the sake of clarity and fitting in with the way that people actually look at these figures. So long as the second in question is not double counted I don’t think it matters that it’s location is indeterminate. ( In contrast this wouldn’t be acceptable for age ranges (0-65, 65-70).)
In doing this I revert to rounding the start of each round. That accords then with the MinuteOfHour value which looks more logical when viewing the table as a whole.
So that leaves
- 0 – 59 secs
- 1 – 2 mins [60 – 119 secs]
- 2 – 5 mins
- 45 – 60 mins
- 60 – 90 mins
- 90 mins – 1 hour
Creation Script
IF ( (SELECT COUNT(*) AS C FROM dbo.DimDuration) = 0 ) BEGIN print 'Seed DimDuration...'; INSERT DimDuration ( [Seconds], [Minutes], Hours, MinuteOfHour, DurationAnalysis1, DurationAnalysis1_MaxSeconds ) VALUES ( 0, 0, 0, 0, '0 secs', 0 ); WITH Pass0 as (select 1 as C union all select 1), --2 rows Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows Tally as (select row_number() over(order by C) as Number from Pass4) INSERT DimDuration ( [Seconds], [Minutes], Hours, MinuteOfHour, DurationAnalysis1, DurationAnalysis1_MaxSeconds ) SELECT TOP(15000) Number, Number / 60, Number / (60 * 60), (Number / 60) % 60, CASE WHEN (Number) < 60 THEN '1 - 59 secs' WHEN (Number) < 120 THEN '1 - 2 mins' WHEN (Number / 60) < 3 THEN '2 - 3 mins' WHEN (Number / 60) < 4 THEN '3 - 4 mins' WHEN (Number / 60) < 5 THEN '4 - 5 mins' WHEN (Number / 60) < 6 THEN '5 - 6 mins' WHEN (Number / 60) < 7 THEN '6 - 7 mins' WHEN (Number / 60) < 8 THEN '7 - 8 mins' WHEN (Number / 60) < 9 THEN '8 - 9 mins' WHEN (Number / 60) < 10 THEN '9 - 10 mins' WHEN (Number / 60) < 15 THEN '10 - 15 mins' WHEN (Number / 60) < 20 THEN '15 - 20 mins' WHEN (Number / 60) < 30 THEN '20 - 30 mins' WHEN (Number / 60) < 40 THEN '30 - 40 mins' WHEN (Number / 60) < 50 THEN '40 - 50 mins' WHEN (Number / 60) < 60 THEN '50 - 60 mins' WHEN (Number / 60) < 90 THEN '60 - 90 mins' WHEN (Number / 60) < 120 THEN '90 mins - 2 hours' WHEN (Number / (60 * 60)) < 3 THEN '2 - 3 hours' WHEN (Number / (60 * 60)) < 4 THEN '3 - 4 hours' WHEN (Number / (60 * 60)) < 10 THEN '4 - 10 hours' WHEN (Number / (60 * 60)) < 15 THEN '10 - 15 hours' WHEN (Number / (60 * 60)) < 24 THEN '15 - 24 hours' ELSE 'over 24 hours' END ,0 FROM Tally; -- Add a column that can be used as a sort-key for ranges. WITH CTE AS ( SELECT DurationAnalysis1, DurationAnalysis1_MaxSeconds = MAX(Seconds) FROM dbo.DimDuration GROUP BY DurationAnalysis1 ) UPDATE DD SET DurationAnalysis1_MaxSeconds = CTE.DurationAnalysis1_MaxSeconds FROM DimDuration DD INNER JOIN CTE ON DD.DurationAnalysis1 = CTE.DurationAnalysis1; print 'Seed DimDuration complete.';