Reputation: 644
I have a table in MS Access which holds staff details (tblStaff):
| Employee Number | Employee Name | Dept |
------------------------------------------------
| 205147 | Joe Bloggs | IT |
| 205442 | John Doe | Accounts |
I refresh this table with new data weekly and if any records have changed (e.g. changed dept) then they are archived in another table (tblArchiveStaff) along with the dates that that record was valid from and to.
| Employee Number | Employee Name | Dept | DateFrom | DateTo |
----------------------------------------------------------------------
| 205147 | Joe Bloggs | HR | 03/01/16 | 01/06/17 |
I am trying to write a query that will select records from either of these tables based on which ones were valid for a given date
We can assume that records in tblStaff are valid from the dateTo + 1 of the last entry for that employee in tblArchiveStaff, or from 03 Jan 16 if they have no archived records.
So far I have come up with the below query into which I have hardcoded the date condition of #07/01/2017#:
SELECT [Employee Number], [Dept], DateFrom, DateTo
FROM
(
SELECT ts.[Employee Number], ts.[Dept], nz(ta2.DateTo,#01/02/16#)+1 AS DateFrom, date() AS DateTo
FROM tblStaff ts LEFT JOIN tblArchiveStaff ta2 ON ts.[Employee Number] = ta2.[Employee Number]
UNION ALL
SELECT ta.[Employee Number], ta.[Dept], ta.DateFrom, ta.DateTo
FROM tblArchiveStaff ta
) AS tblUnion
WHERE #07/01/2017# BETWEEN DateFrom AND DateTo;
As I understand it the above query should return records valid on July 1st 2017 which would be both records in tblStaff, it is however returning the record in tblArchiveStaff. It is almost like it is treating the date condition as 7 January which would mean it is formatted dd/mm/yyyy which I thought was impossible.
Can anyone explain this please?
Upvotes: 2
Views: 938
Reputation: 55841
That is because you don't play by the rules. Always handle dates as date values, not strings, not numbers, no exceptions.
So, when you use Nz and even add 1, the union query cannot figure out the datatype, thus it falls back to return the result as text. Then DateFrom becomes Text while DateTo is Date which makes filtering a wild guess.
*Edit - I have also amended the first part of the union query to ensure the current record follows on from the most recent archived record)
Correct as this:
SELECT
tblUnion.[Employee Number],
tblUnion.[Dept],
tblUnion.DateFrom,
tblUnion.DateTo
FROM
(SELECT
ts.[Employee Number],
ts.[Dept],
DateAdd("d", 1, Nz(ta2.MaxDateTo, #01/02/16#)) AS DateFrom,
Date() AS DateTo
FROM
tblStaff ts
LEFT JOIN
(SELECT
[Employee Number],
max(DateTo) AS MaxDateTo
FROM
tblArchiveStaff
GROUP BY
[Employee Number]) ta2
ON ts.[Employee Number] = ta2.[Employee Number]
UNION ALL
SELECT
ta.[Employee Number],
ta.[Dept],
ta.DateFrom,
ta.DateTo
FROM
tblArchiveStaff ta) AS tblUnion
WHERE
#7/1/2017# Between [DateFrom] And [DateTo];
and you will get the desired output:
Employee Number Dept DateFrom DateTo
205147 IT 2017-01-07 2017-07-05
205442 Accounts 2016-01-03 2017-07-05
Upvotes: 3
Reputation: 2922
Standard date flipping errors. Try to always use neutral date formats in your code like
d MMM yyyy
1 Jul 2017
(viable but not recommended because of language differences)
or
yyyy-MM-dd
2017-07-01
(recommended, will work everywhere)
Upvotes: 0