Reputation: 373
Similar to the following:
Count days within a month from date range
I want to find a way, within the MS-Access Query Design environment, to create fields that count the number of month/year days within a date range.
Here is what I want the data to look like:
Row | StartDate | EndDate | #DaysJan2010 | #DaysFeb2010 | #DaysMarch2010
001 01/02/2010 02/04/2012 29 28 31
002 01/02/2010 01/05/2010 4 0 0
003 04/02/2010 05/05/2010 0 0 0
004 01/02/2010 02/04/2012 29 28 31
005 02/02/2012 02/03/2012 0 2 0
Please keep in mind that both month and year are important because I need to be able to distinguish between the number of days that fall within a given date range for January 2010 and January 2011, as opposed to just the number of days within a given date range that are in January.
If there is a systematic way of performing of creating these fields by using SQL in Access, that would be my preferred method.
However, in the event that it is impossible (or very difficult) to do so, I would like to know how to build each field in the expression builder, so that I may at least be able to generate the count fields one at a time.
As always, thank you very much for your time.
Upvotes: 2
Views: 659
Reputation: 123409
There are cases where date manipulations can be aided by a "dates table". Similar to a "numbers table", a "dates table" is a table containing one row for every date in a given range, usually covering the entire range of dates that one could expect to encounter in the actual data.
For sample data in a table named [SampleData]
Row StartDate EndDate
--- ---------- ----------
001 2010-01-02 2012-02-04
002 2010-01-02 2010-01-05
003 2010-04-02 2010-05-05
004 2010-01-02 2012-02-04
005 2012-02-02 2012-02-03
and a [DatesTable] that is simply
theDate
----------
2010-01-01
2010-01-02
2010-01-03
...
2012-12-30
2012-12-31
the query
SELECT
sd.Row,
dt.theDate,
Year(dt.theDate) AS theYear,
Month(dt.theDate) AS theMonth
FROM
SampleData AS sd
INNER JOIN
DatesTable AS dt
ON dt.theDate >= sd.StartDate
AND dt.theDate <= sd.EndDate
returns a row for each date in the interval for each [SampleData].[Row] value. (For this particular sample data, that's 1568 rows in total.)
Performing an aggregation on that
SELECT
Row,
theYear,
theMonth,
COUNT(*) AS NumberOfDays
FROM
(
SELECT
sd.Row,
dt.theDate,
Year(dt.theDate) AS theYear,
Month(dt.theDate) AS theMonth
FROM
SampleData AS sd
INNER JOIN
DatesTable AS dt
ON dt.theDate >= sd.StartDate
AND dt.theDate <= sd.EndDate
) AS allDates
GROUP BY
Row,
theYear,
theMonth
gives us all of the counts
Row theYear theMonth NumberOfDays
--- ------- -------- ------------
001 2010 1 30
001 2010 2 28
001 2010 3 31
001 2010 4 30
001 2010 5 31
001 2010 6 30
001 2010 7 31
001 2010 8 31
001 2010 9 30
001 2010 10 31
001 2010 11 30
001 2010 12 31
001 2011 1 31
001 2011 2 28
001 2011 3 31
001 2011 4 30
001 2011 5 31
001 2011 6 30
001 2011 7 31
001 2011 8 31
001 2011 9 30
001 2011 10 31
001 2011 11 30
001 2011 12 31
001 2012 1 31
001 2012 2 4
002 2010 1 4
003 2010 4 29
003 2010 5 5
004 2010 1 30
004 2010 2 28
004 2010 3 31
004 2010 4 30
004 2010 5 31
004 2010 6 30
004 2010 7 31
004 2010 8 31
004 2010 9 30
004 2010 10 31
004 2010 11 30
004 2010 12 31
004 2011 1 31
004 2011 2 28
004 2011 3 31
004 2011 4 30
004 2011 5 31
004 2011 6 30
004 2011 7 31
004 2011 8 31
004 2011 9 30
004 2011 10 31
004 2011 11 30
004 2011 12 31
004 2012 1 31
004 2012 2 4
005 2012 2 2
We can then report on that, or crosstab it, or do any number of other fun things.
Side note:
One circumstance where a "dates table" can be very useful is when we have to deal with Statutory Holidays. That is because
Sometimes the "day off" for a Statutory Holiday is not the actual day. If "International Bacon Day" falls on a Sunday then we might get the Monday off.
Some Statutory Holidays can be tricky to calculate. For example, Good Friday for us Canadians is (if I remember correctly) "the Friday before the first Sunday after the first full moon after the Spring Equinox".
If we have a "dates table" then we can add a [StatutoryHoliday] Yes/No
field to flag all of the (observed) holidays and then use ... WHERE NOT StatutoryHoliday
to exclude them.
Upvotes: 2