Count criteria: A \"true\" count, by month-year, of the number of students (indexed by a unique Student ID) at each School by School Service Type.
I am currently usi
Here's one way to tackle it. For sample data in a table named [Payments]
Payment Row Student ID School School Service Type PaymentStartDate PaymentEndDate
----------- ---------- ------ ------------------- ---------------- --------------
1 001 ABC ED 2010-01-02 2012-02-04
2 001 ABC ED 2010-01-02 2010-01-05
3 001 ABC ED 2010-04-02 2010-05-05
4 001 DEF EZ 2010-01-02 2012-02-04
5 001 RR 2012-02-02 2012-02-03
6 002 ABC ED 2010-02-02 2011-02-03
7 002 ABC EZ 2010-02-02 2010-06-03
8 002 GHI ED 2011-02-04 2012-02-04
9 003 ABC ED 2011-02-02 2012-02-03
10 003 DEF ED 2010-01-02 2010-08-03
11 003 RR 2011-02-02 2011-02-03
12 004 RR 2011-02-02 2011-02-03
13 005 GHI ED 2010-08-02 2011-02-04
14 006 GHI ED 2010-08-02 2010-08-02
if we create a saved query in Access named [PaymentsYearMonth]
SELECT
[Student ID],
School,
[School Service Type],
(Year(PaymentStartDate) * 100) + Month(PaymentStartDate) AS StartYYYYMM,
(Year(PaymentEndDate) * 100) + Month(PaymentEndDate) AS EndYYYYMM
FROM Payments
it will give us
Student ID School School Service Type StartYYYYMM EndYYYYMM
---------- ------ ------------------- ----------- ---------
001 ABC ED 201001 201202
001 ABC ED 201001 201001
001 ABC ED 201004 201005
001 DEF EZ 201001 201202
001 RR 201202 201202
002 ABC ED 201002 201102
002 ABC EZ 201002 201006
002 GHI ED 201102 201202
003 ABC ED 201102 201202
003 DEF ED 201001 201008
003 RR 201102 201102
004 RR 201102 201102
005 GHI ED 201008 201102
006 GHI ED 201008 201008
To generate the Year/Month pairs that the data covers, we can use a table named [MonthNumbers]
MonthNumber
-----------
1
2
3
4
5
6
7
8
9
10
11
12
and a table named [YearNumbers] which covers every year that might possibly appear in the data. For safety one might include every year from, say, 1901 to 2525, but for illustration we'll just use
YearNumber
----------
2009
2010
2011
2012
2013
Now we can create a saved query named [MonthsToReport] to give us the rows that might have results
SELECT
yn.YearNumber,
mn.MonthNumber,
(yn.YearNumber * 100) + mn.MonthNumber AS YYYYMM
FROM
YearNumbers AS yn,
MonthNumbers AS mn
WHERE ((yn.YearNumber * 100) + mn.MonthNumber)>=DMin("StartYYYYMM","PaymentsYearMonth")
AND ((yn.YearNumber * 100) + mn.MonthNumber)<=DMax("EndYYYYMM","PaymentsYearMonth")
Sorted by Year and Month that would look like
YearNumber MonthNumber YYYYMM
---------- ----------- ------
2010 1 201001
2010 2 201002
2010 3 201003
2010 4 201004
2010 5 201005
2010 6 201006
2010 7 201007
2010 8 201008
2010 9 201009
2010 10 201010
2010 11 201011
2010 12 201012
2011 1 201101
2011 2 201102
2011 3 201103
2011 4 201104
2011 5 201105
2011 6 201106
2011 7 201107
2011 8 201108
2011 9 201109
2011 10 201110
2011 11 201111
2011 12 201112
2012 1 201201
2012 2 201202
Now to create a query that gives us distinct instances of Year/Month/Student/School/Type
SELECT DISTINCT
mtr.YearNumber,
mtr.MonthNumber,
pym.[Student ID],
pym.School,
pym.[School Service Type]
FROM
MonthsToReport AS mtr
INNER JOIN
PaymentsYearMonth AS pym
ON mtr.YYYYMM>=pym.StartYYYYMM
AND mtr.YYYYMM<=pym.EndYYYYMM
...wrap that in an aggregation query to count up the (now unique) [Student ID] values
SELECT
YearNumber,
MonthNumber,
School,
[School Service Type],
COUNT(*) AS CountOfStudents
FROM
(
SELECT DISTINCT
mtr.YearNumber,
mtr.MonthNumber,
pym.[Student ID],
pym.School,
pym.[School Service Type]
FROM
MonthsToReport AS mtr
INNER JOIN
PaymentsYearMonth AS pym
ON mtr.YYYYMM>=pym.StartYYYYMM
AND mtr.YYYYMM<=pym.EndYYYYMM
) AS distinctQuery
GROUP BY
YearNumber,
MonthNumber,
School,
[School Service Type]
and then use that as the FROM subquery in our crosstab query
TRANSFORM Nz(First(CountOfStudents),0) AS n
SELECT
YearNumber,
MonthNumber,
School
FROM
(
SELECT
YearNumber,
MonthNumber,
School,
[School Service Type],
COUNT(*) AS CountOfStudents
FROM
(
SELECT DISTINCT
mtr.YearNumber,
mtr.MonthNumber,
pym.[Student ID],
pym.School,
pym.[School Service Type]
FROM
MonthsToReport AS mtr
INNER JOIN
PaymentsYearMonth AS pym
ON mtr.YYYYMM>=pym.StartYYYYMM
AND mtr.YYYYMM<=pym.EndYYYYMM
) AS distinctQuery
GROUP BY
YearNumber,
MonthNumber,
School,
[School Service Type]
) AS countQuery
GROUP BY
YearNumber,
MonthNumber,
School
PIVOT [School Service Type]
returning
YearNumber MonthNumber School ED EZ RR
---------- ----------- ------ -- -- --
2010 1 ABC 1 0 0
2010 1 DEF 1 1 0
2010 2 ABC 2 1 0
2010 2 DEF 1 1 0
2010 3 ABC 2 1 0
2010 3 DEF 1 1 0
2010 4 ABC 2 1 0
2010 4 DEF 1 1 0
2010 5 ABC 2 1 0
2010 5 DEF 1 1 0
2010 6 ABC 2 1 0
2010 6 DEF 1 1 0
2010 7 ABC 2 0 0
2010 7 DEF 1 1 0
2010 8 ABC 2 0 0
2010 8 DEF 1 1 0
2010 8 GHI 2 0 0
2010 9 ABC 2 0 0
2010 9 DEF 0 1 0
2010 9 GHI 1 0 0
2010 10 ABC 2 0 0
2010 10 DEF 0 1 0
2010 10 GHI 1 0 0
2010 11 ABC 2 0 0
2010 11 DEF 0 1 0
2010 11 GHI 1 0 0
2010 12 ABC 2 0 0
2010 12 DEF 0 1 0
2010 12 GHI 1 0 0
2011 1 ABC 2 0 0
2011 1 DEF 0 1 0
2011 1 GHI 1 0 0
2011 2 0 0 2
2011 2 ABC 3 0 0
2011 2 DEF 0 1 0
2011 2 GHI 2 0 0
2011 3 ABC 2 0 0
2011 3 DEF 0 1 0
2011 3 GHI 1 0 0
2011 4 ABC 2 0 0
2011 4 DEF 0 1 0
2011 4 GHI 1 0 0
2011 5 ABC 2 0 0
2011 5 DEF 0 1 0
2011 5 GHI 1 0 0
2011 6 ABC 2 0 0
2011 6 DEF 0 1 0
2011 6 GHI 1 0 0
2011 7 ABC 2 0 0
2011 7 DEF 0 1 0
2011 7 GHI 1 0 0
2011 8 ABC 2 0 0
2011 8 DEF 0 1 0
2011 8 GHI 1 0 0
2011 9 ABC 2 0 0
2011 9 DEF 0 1 0
2011 9 GHI 1 0 0
2011 10 ABC 2 0 0
2011 10 DEF 0 1 0
2011 10 GHI 1 0 0
2011 11 ABC 2 0 0
2011 11 DEF 0 1 0
2011 11 GHI 1 0 0
2011 12 ABC 2 0 0
2011 12 DEF 0 1 0
2011 12 GHI 1 0 0
2012 1 ABC 2 0 0
2012 1 DEF 0 1 0
2012 1 GHI 1 0 0
2012 2 0 0 1
2012 2 ABC 2 0 0
2012 2 DEF 0 1 0
2012 2 GHI 1 0 0