0

I am trying to return an Employee Name and Award Date if they have no prior award dates before dates the user specifies (these are fields on a form, StartDateTxt and EndDateTxt as seen below), aka their "first occurrence."

Example (AwardTbl only for simplicity):

AwardDate   EmployeeID  PlanID   AwardedUnits
3/1/2005    100200         1          3
3/1/2008    100200         1          7
3/1/2005    100300         1          5
3/1/2013    100300         1          8

If I ran the query between the dates 1/1/2005 - 12/31/2005, it would return 3/1/2005 and 100200 and 100300. If I ran the query between 1/1/2008-12/31/2008 it would return nothing and likewise with 1/1/2013 - 12/31/2013 because those employees have already had an earlier award date.

I tried a couple different things, which gave me some weird results.

SELECT x.AstFirstName ,
       x.AstLastName ,
       y.AwardDate ,
       y.AwardUnits ,
       z.PlanDesc
FROM (AssociateTbl AS x
      INNER JOIN AwardTbl AS y ON x.EmployeeID = y.EmployeeID)
INNER JOIN PlanTbl AS z ON y.PlanID = z.PlanID
WHERE y.AwardDate BETWEEN [Forms]![PlanFrm]![ReportSelectSbfrm].[Form]![StartDateTxt] And [Forms]![PlanFrm]![ReportSelectSbfrm].[Form]![EndDateTxt] ;

This query did NOT care if there was previous record or not, and I think that's where I am unsure of how to narrow down the query.

I also tried :

  1. Min(AwardDate) (didn't work)
  2. A subquery in the WHERE clause that ordered by TOP 1 AwardDate ASC, which only returned 1 record
  3. A DCount("*", "AwardTbl", "AwardDate < [Forms]![PlanFrm]![ReportSelectSbfrm].[Form]![StartDateTxt]") < 1 (This also did not differentiate whether or not it was the first occurrence of the AwardDate)

Please note: This is MS Access. There is no ROW_NUMBER() or CTE features.

Mark C.
  • 6,332
  • 4
  • 35
  • 71

3 Answers3

1

Try like below

SELECT x.AstFirstName ,
       x.AstLastName ,
       y.AwardDate ,
       y.AwardUnits ,
       z.PlanDesc
FROM (AssociateTbl AS x
INNER JOIN AwardTbl AS y 
ON x.EmployeeID = y.EmployeeID)
INNER JOIN PlanTbl AS z 
ON y.PlanID = z.PlanID
WHERE y.AwardDate BETWEEN '1/1/2005' AND '12/31/2005'
GROUP BY y.EmployeeID,
       x.AstFirstName ,
       x.AstLastName ,
       y.AwardDate ,
       y.AwardUnits ,
       z.PlanDesc
HAVING COUNT(*) = 1
Rahul
  • 76,197
  • 13
  • 71
  • 125
  • Immediately I get an error: `Syntax error (missing operator) in query expression x.EmployeeID = y.EmployeeID INNER JOIN PlanTbl AS z ON y.PlanID = z.PlanID.` – Mark C. Apr 14 '14 at 17:39
  • Another error: You tried to execute a query that does not include the specified expression 'AstFirstName' as part of an aggregate function. – Mark C. Apr 14 '14 at 18:05
  • Now: Data type mismatch in criteria expression. – Mark C. Apr 14 '14 at 18:07
  • @Newbie, it was error'ng cause the column included in select list wasn't there in group by. should be fine now. data type mismatch most probably cause of this line `y.AwardDate BETWEEN '1/1/2005' AND '12/31/2005'`. You can replace the hardcoded dates to your own inout. – Rahul Apr 14 '14 at 18:08
  • I still get the Data type mismatch error. It's not providing any hints other than that. – Mark C. Apr 14 '14 at 18:12
1

I believe you need a nested select. The nested query will select with Min(awardDate), and the outer query will filter for the time period you want.

If you have both in the same query, it'll filter out the results before it does Min(awardDate) returning you the Min(awardDate) in your specified time.

select y.employeeId, y.awardDate from (
  select x.employeeId, min(x.awardDate) as awardDate 
    from AssociateTbl as x 
    group by x.employeeId) as y 
where y.awardDate >= :startAwardDate and y.awardDate < :endAwardDate;
Tony Meng
  • 353
  • 4
  • 12
  • Yes, I think we're on the same page. Do you know how I should go about this? (I'm not great at SQL). – Mark C. Apr 14 '14 at 17:37
  • syntax may be a little off depending on what database you're using, but in general, it should look like this select y.employeeId, y.awardDate from ( select x.employeeId, min(x.awardDate) from AssociateTbl as x group by x.employeeId) as y where y.awardDate >= :startAwardDate and y.awardDate < :endAwardDate; – Tony Meng Apr 14 '14 at 17:44
  • Hm. It's not recognizing `y.AwardDate` in the first `SELECT` – Mark C. Apr 14 '14 at 17:51
  • sorry, the nested query does a min(x.awardDate) without re-labeling it as awardDate so if you do `select x.employeeId, min(x.awardDate) as awardDate...` it should work `select y.employeeId, y.awardDate from ( select x.employeeId, min(x.awardDate) as awardDate from AssociateTbl as x group by x.employeeId) as y where y.awardDate >= :startAwardDate and y.awardDate < :endAwardDate;` – Tony Meng Apr 14 '14 at 17:56
  • I think you got it, sir. Let me check a couple different parameters. – Mark C. Apr 14 '14 at 18:06
  • 1
    @tony, try moving your code samples from comment to your answer. So that, you have it in one place and in future people don't have to go through the comment threads to get the zist. – Rahul Apr 14 '14 at 18:10
  • Actually, it did not get all the records when I tried some different parameters. It worked for the first 4 I tried, but it omitted records on another attempt with different dates. – Mark C. Apr 14 '14 at 18:22
  • can you post examples of things it omitted? – Tony Meng Apr 14 '14 at 18:33
  • Actually, it seems to be working correctly. Do you have any clue on the joins? – Mark C. Apr 14 '14 at 18:52
  • I gave the answer to Ron because of the completeness of his answer (all joins fully functioning, etc.) Thank you for your help, though – Mark C. Apr 14 '14 at 19:35
1

Min Award Date will work if grouped by EmployeeID with your date range in the Having clause and used as a filter list:

SELECT x.AstFirstName ,
       x.AstLastName ,
       y.AwardDate ,
       y.AwardUnits ,
       z.PlanDesc
FROM  ((AssociateTbl AS x
    INNER JOIN AwardTbl AS y ON x.EmployeeID = y.EmployeeID)
    INNER JOIN (select a.EmployeeID,min(a.AwardDate) AS MinAwardDate
                from AwardTbl AS a
                group by a.EmployeeID
                having ((min(a.awardDate)>=[Forms]![PlanFrm]![ReportSelectSbfrm].[Form]![StartDateTxt]
                    and min(a.awardDate)<[Forms]![PlanFrm]![ReportSelectSbfrm].[Form]![EndDateTxt]))
               ) AS d on d.EmployeeID = x.EmployeeID
                   and d.MinAwardDate = y.AwardDate)
    INNER JOIN PlanTbl AS z ON y.PlanID = z.PlanID
Ron Smith
  • 3,241
  • 1
  • 13
  • 16
  • See my note at the bottom of my post. This is MS Access. – Mark C. Apr 14 '14 at 17:50
  • Yeah, I can do that. I think the formatting is a little different but not much than other major DBs. – Mark C. Apr 14 '14 at 17:52
  • I receive the same error I received with Rahul's code.`Syntax error (missing operator in query expression x.EmployeeID = y.EmployeeID INNER JOIN PlanTbl AS z ON y.PlanID = z.PlanID` – Mark C. Apr 14 '14 at 17:55
  • Hmm... you don't get that error with your original code? I have updated the sql to join the AwardDate along with the EmployeeID so you only get the Award record of the first Award date. – Ron Smith Apr 14 '14 at 17:57
  • Apparently, you need parenthesis around your joins in Access: http://stackoverflow.com/questions/10852499/access-2010-syntax-error-missing-operator-in-query-expression Try adding those and let me know if you can get it to work. I've never done SQL in Access before. – Ron Smith Apr 14 '14 at 18:00
  • I think the updated code should work. Each join has to be nested in a set of brackets: http://stackoverflow.com/questions/7854969/sql-multiple-join-statement – Ron Smith Apr 14 '14 at 18:02
  • Yeah I think that's what was throwing the error. I am checking Tony's solution, because I think it could work. Then I will check yours. Thanks – Mark C. Apr 14 '14 at 18:02
  • So with yours, I am getting another error: "Circular reference caused by alias 'AwardDate' in query definition's SELECT list." – Mark C. Apr 14 '14 at 18:04
  • I wonder if changing the name of the column in the subquery will work. Maybe self-joins aren't allowed in Access? – Ron Smith Apr 14 '14 at 18:09
  • I know self joins are allowed because I have done it a couple other times. I think it has something to do with needing to rename the AwardTbl in the Subquery? – Mark C. Apr 14 '14 at 18:11
  • Updated. I gave the AwardTbl in the subquery an alias. I think that is it. – Ron Smith Apr 14 '14 at 18:12
  • 1
    Still got an error. Let me try to add in the keywords `AS` (required in Access) – Mark C. Apr 14 '14 at 18:15
  • Updated to us `AS` on the table and subquery aliases. – Ron Smith Apr 14 '14 at 18:18
  • Ah... It is not liking the Min(a.AwardDate).. The Microsoft Access database engine could not find the object 'min(a.AwardDate) MinAwardDate'. Make sure the object exists and that you spell its name and path name correctly." I then tried to put `AS MinAwardDate` and it gave me a Data Type mismatch error. – Mark C. Apr 14 '14 at 18:21
  • Tony's answer actually omitted records, thus I had to unaccept it. – Mark C. Apr 14 '14 at 18:23
  • I'll update the sql for date formatting. Apparently, Access requires hashtags around dates: http://stackoverflow.com/questions/19809986/sql-access-2010-querying-by-date-data-type-mismatch-in-criteria-expression – Ron Smith Apr 14 '14 at 18:59
  • The hashtags aren't necessary. I am referencing fields on a form, not actual dates. – Mark C. Apr 14 '14 at 19:01
  • Well AwardTbl.AwardDate **is** a date. However, I am not passing parameters via `#Date#`.. I am passing them in the `WHERE` clause like this (and it's working): `WHERE (((y.awardDate)>=[Forms]![PlanFrm]![ReportSelectSbfrm].[Form]![StartDateTxt] And (y.awardDate)<[Forms]![PlanFrm]![ReportSelectSbfrm].[Form]![EndDateTxt]));` – Mark C. Apr 14 '14 at 19:04
  • I accepted your answer because it was more complete and fully answered the question. Thanks for sticking it out with me! – Mark C. Apr 14 '14 at 19:34