Snayff
Snayff

Reputation: 97

Finding Consecutive and single instance dates, between two dates, in Access(SQL)

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

Answers (2)

Tom Sharpe
Tom Sharpe

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

enter image description here

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

Snayff
Snayff

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:

  • Created a new table to hold the dates required.
  • Run a query held in Access, from Excel to append the required records, between the date points, in to the new table.
  • Run a Select query from Excel to return the instances, excluding Sundays.

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

Related Questions