Reputation: 97
Morning all,
I want to know every instance of absence, where an instance is any single day or set of consecutive days, between two date points. I had extensive help on this in my original question and have working code for everything except the "Between two dates" part. I am hoping someone can help me to add the "between two dates" element to the working code.
Example question:
How many instances, and total days, of absence has everyone had between 03/01/16 and 19/01/16?
Sample data:
|IDRef |RecordDate |Racf |Type |LengthOfAbsence
|1788 |04-Jan-16 |Bob |Sickness |420
|1789 |04-Jan-16 |Jill |Sickness |420
|1790 |05-Jan-16 |Bob |Sickness |420
|1791 |17-Jan-16 |Jill|Sickness |420
|1792 |18-Jan-16 |Bob |Sickness |420
Expected output:
| Racf |Total Days |Instances
|Bob | 3 |2
|Jill |2 |2
Working code:
SELECT Absence.Racf, Count(Absence.RecordDate) AS CountOfRecordDate
FROM Absence LEFT JOIN (select Racf, [RecordDate]+IIf(Weekday([RecordDate],7)=1,2,1) as RecordDate2 from Absence) AS t2 ON (Absence.RecordDate = t2.RecordDate2) AND (Absence.Racf = t2.Racf)
WHERE (((t2.RecordDate2) Is Null))
GROUP BY Absence.Racf;
My most recent attempt to amend it to only look between two dates (this doesn't cause an error but does return unexpected/incorrect values):
Sql = "SELECT Absence.Racf, Count(Absence.RecordDate) AS CountOfRecordDate "
Sql = Sql & "FROM Absence LEFT JOIN (select Racf, [RecordDate]+IIf(Weekday([RecordDate],7)=1,2,1) as RecordDate2 from Absence where [RecordDate] BETWEEN #" & sFromDate & "# AND #" & sToDate & "#) AS t2 ON (Absence.RecordDate = t2.RecordDate2) AND (Absence.Racf = t2.Racf) "
Sql = Sql & "WHERE (((t2.RecordDate2) Is Null)) AND [t2.RecordDate2] BETWEEN #" & sFromDate & "# AND #" & sToDate & "# "
Sql = Sql & "GROUP BY Absence.Racf;"
Original question here: Count instances of consecutive dates for associated name (VBA, SQL)
Any help with this last step would be greatly appreciated, an explanation of why it works wouldn't hurt, either, as I have no idea!
Upvotes: 1
Views: 515
Reputation: 34230
Here is my new working code that I have tested in Access but not yet in a macro called from Excel
SELECT Absence.Racf, Count(Absence.RecordDate) AS CountOfRecordDate, Absence.RecordDate
FROM Absence LEFT JOIN [select Racf, [RecordDate]+IIf(Weekday([RecordDate],7)=1,2,1) as RecordDate2 from Absence]. AS t2 ON (Absence.Racf = t2.Racf) AND (Absence.RecordDate = t2.RecordDate2)
WHERE (((t2.RecordDate2) Is Null))
GROUP BY Absence.Racf, Absence.RecordDate
HAVING (((Absence.RecordDate)>#1/1/2016# And (Absence.RecordDate)<#10/11/2016#));
The reason a date range didn't work in the WHERE clause was that the date here is always NULL so you never get any records.
You could equally well use a BETWEEN statement instead of > and <.
I'm sorry this isn't the neat solution you were looking for, but this is getting beyond what you can easily do in a single query in Access. The output looks like this
What I suggest you do (if you imagine this for several users) is to use a pivot table to summarise the results for each user.
But you may also try this
SQL = "select racf, count(racf) AS Instances from ("
SQL = SQL & "SELECT Absence.Racf, Count(Absence.RecordDate) AS CountOfRecordDate,Absence.RecordDate"
SQL = SQL & " FROM (Absence LEFT JOIN (select Racf, RecordDate+IIf(Weekday([RecordDate],7)=1,2,1) as RecordDate1 from Absence) AS t1 ON (Absence.RecordDate = t1.RecordDate1) AND (Absence.Racf = t1.Racf))"
SQL = SQL & " WHERE ((t1.RecordDate1) Is Null) "
SQL = SQL & " GROUP BY Absence.Racf,Absence.RecordDate"
SQL = SQL & " HAVING (((Absence.RecordDate)>#1/1/2016# And (Absence.RecordDate)<#10/11/2016#))"
SQL = SQL & ") AS T0 GROUP BY RACF"
EDIT
I'm sure on reflection that although correct, this can be simplified because the inner GROUP BY isn't serving any useful purpose - the HAVING clause should be brought outside T0 as a WHERE clause.
It should look like this
SQL = "select racf, count(racf) AS Instances from ("
SQL = SQL & "SELECT Absence.Racf, Absence.RecordDate"
SQL = SQL & " FROM (Absence LEFT JOIN (select Racf, RecordDate+IIf(Weekday([RecordDate],7)=1,2,1) as RecordDate1 from Absence) AS t1 ON (Absence.RecordDate = t1.RecordDate1) AND (Absence.Racf = t1.Racf))"
SQL = SQL & " WHERE ((t1.RecordDate1) Is Null) "
SQL = SQL & ") AS T0 WHERE (((RecordDate)>#1/1/2016# And (RecordDate)<#10/11/2016#))"
SQL = SQL & "GROUP BY RACF"
EDIT
Have now tested this and it does work but a date like #10/11/2016# is ambiguous - although my locale is UK it appeared to be interpreted as October 11th 2016.
Suggest using instead
Datevalue(""10 November 2016"")
where quotes have to be doubled up because they appear in a quoted string.
Upvotes: 1
Reputation: 97
Thanks to Tom's answers I finally got there.
To retrieve instances of individual or consecutive dates, within a date range, here is what worked:
To run the query from Excel (db already defined as OpenDatabase):
db.QueryDef.Execute
Append query:
INSERT INTO AbsenceInstances ( Racf, RecordDate )
SELECT Absence.Racf, Absence.RecordDate
FROM Absence
WHERE ((Absence.RecordDate)>=#01/01/2017# And (Absence.RecordDate)<=#28/03/2017#);
Select Query:
Sql = "SELECT AbsenceInstances.Racf, Count(AbsenceInstances.RecordDate) AS CountOfRecordDate"
Sql = Sql & " FROM AbsenceInstances LEFT JOIN (select Racf, [RecordDate]+IIf(Weekday([RecordDate],7)=1,2,1) as RecordDate2 from AbsenceInstances) AS t2 ON (AbsenceInstances.RecordDate = t2.RecordDate2) AND (AbsenceInstances.Racf = t2.Racf)"
Sql = Sql & " WHERE (((t2.RecordDate2) Is Null))"
Sql = Sql & " GROUP BY AbsenceInstances.Racf;"
Can't thank Tom enough for his help. I hope this summation is useful for anyone else in the future.
Upvotes: 1