473,387 Members | 1,497 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Query to find max date value for an ID in a linked table

16
Hi all! I wonder if anyone could offer advice - I am not exactly an SQL gun and have been playing with this for a day now. Any nudges in the right direction would be very much appreciated.

I am trying to create a query based on 2 linked tables, that gives me a grouped list of IDs from table 1 and a the latest date in table 2 for a row that has the same ID as table 1

So for example I have 2 tables.

table1 includes
MyID - primary key
MyName


table2 includes
ID
MyID - foreign key
MyDate
MyComment

I want to find table2.MyComment for the latest table2.MyDate where table2.MyID matches table1.MyID (eg the grouping level).

So say table1 is
Expand|Select|Wrap|Line Numbers
  1. MyID    Myname
  2. 1    name1
  3. 2    name2
and table2 is
Expand|Select|Wrap|Line Numbers
  1. ID    MyID    MyDate    MyComment
  2. 1    1    1/1/12    Comment1
  3. 2    1    2/1/12    Comment2
  4. 3    2    1/1/12    Comment3
My query should return

Expand|Select|Wrap|Line Numbers
  1. MyID    MyName    MyComment
  2. 1    name1    Comment2
  3. 2    name2    Comment3
I have been able to achieve this using the following:
Expand|Select|Wrap|Line Numbers
  1. =Dlookup("[MyComment]","table2","[MyID] = " & [MyID] & " And datevalue([MyDate]) = #" & format(dmax("[MyDate]","table2","[MyID] = " & [MyID]),"mm/dd/yyyy") & "#")
in a continuous form with table1 as the recordsource but it is very slow, so I'm hoping to replace this with a single query I can use as the recordsource.

Where I am stuck is what syntax to use for the query. In single instances of dcount in a continuous form I can just refer to a field in the current row, if that makes sense but not sure how to do it in SQL.

I have got as far as this

Expand|Select|Wrap|Line Numbers
  1. SELECT table1.myID
  2. , table1.MyName
  3. , table2.MyComment WHERE MyDate = MAX(SELECT MyDate FROM table2 WHERE table2.MyID = table1.MyID)
  4. FROM table1 INNER JOIN table2 ON table1.MyID = table2.MyID
  5. GROUP BY table1.MyID;
But this gives me a syntax error (missing operator) in the WHERE statement, I suspect I am referencing the tables and fields wrong and I also wonder if there is a completely different way to go about this?

I have also tried using the query builder but with no success yet. I have had a search on this forum but I could only find examples querying a single table.
Sep 19 '12 #1

✓ answered by zmbd

The way I think of these queries is to break them up into small chunks:

Starting with table2:
What you want is the last (max) date of each entry made by the my id. So you need to group on the user ID and return the max date. Call this Q1
(myid,mydate) = (1,2/1/12) and (2,1/1/12)
SQL
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Table2.FK_MyID,
  3.    Max(Table2.MyDate) 
  4.       AS MaxOfMyDate
  5. FROM Table2
  6. GROUP BY Table2.FK_MyID;
This is great now we need the comment associated with these... well only two records will match so do a simple inner join with table2 against the agregate query Q1 on the FK_Myid and the MyDate fields. Show the fields from table 2 that we're interested in. Call this Q2
(PK_tbl2, FK_MyID, MYDate, Comment)=
(2, 1, 2/12/2012, Comment2)
(3, 2, 1/1/2012, Comment3)
SQL

Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Table2.PK_Tbl2, 
  3.    Table2.FK_MyID, 
  4.    Table2.MyDate, 
  5.    Table2.Comment
  6. FROM Table2 
  7.    INNER JOIN Q1 
  8.       ON (Table2.MyDate = Q1.MaxOfMyDate) 
  9.          AND (Table2.FK_MyID = Q1.FK_MyID);
Finally we need to get the names from table one... easy same inner join on table1 and q2 showing the name field from table1 and the date and comment from q2. Call this Q3
(Q2!PK_tbl2, Table1!MyName, Q2!MYDate, Q2!Comment)=
(2, Name1, 2/12/2012, Comment2)
(3, Name2, 1/1/2012, Comment3)

SQL -Q3:
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Q2.PK_Tbl2, 
  3.    Table1.MyName, 
  4.    Q2.MyDate,
  5.     Q2.Comment
  6. FROM Table1 
  7.    INNER JOIN Q2 
  8.       ON Table1.MyID = Q2.FK_MyID;
So the final SQL looks like:
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Q2.PK_Tbl2, 
  3.    Table1.MyName, 
  4.    Q2.MyDate,
  5.     Q2.Comment
  6. FROM Table1 
  7.    INNER JOIN 
  8.    ( SELECT 
  9.        Table2.PK_Tbl2, 
  10.        Table2.FK_MyID, 
  11.        Table2.MyDate, 
  12.        Table2.Comment
  13.     FROM Table2 
  14.        INNER JOIN
  15.           (SELECT 
  16.              Table2.FK_MyID,
  17.              Max(Table2.MyDate) 
  18.       AS MaxOfMyDate
  19.           FROM Table2
  20.           GROUP BY Table2.FK_MyID) 
  21.       AS Q1 
  22.           ON (Table2.MyDate = Q1.MaxOfMyDate) 
  23.              AND (Table2.FK_MyID = Q1.FK_MyID))
  24.     AS Q2 
  25.       ON Table1.MyID = Q2.FK_MyID;
-edit- found typo
Ofcourse, in Q2 you could go ahead and add in table1 to get the name value so you'd get something like:
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Table2.PK_Tbl2, 
  3.    Table1.MyName, 
  4.    Table2.FK_MyID, 
  5.    Table2.MyDate, 
  6.    Table2.Comment
  7. FROM Table1 
  8.    INNER JOIN 
  9.       (Table2 
  10.          INNER JOIN
  11.          (SELECT 
  12.             Table2.FK_MyID,
  13.             Max(Table2.MyDate)
  14.                AS MaxOfMyDate
  15.           FROM Table2
  16.           GROUP BY Table2.FK_MyID)
  17.        AS Q1 
  18.        ON (Table2.MyDate = Q1.MaxOfMyDate) 
  19.           AND (Table2.FK_MyID = Q1.FK_MyID)) 
  20.       ON Table1.MyID = Table2.FK_MyID;
Which I think looks a little neater and one less sub.


Now I'm sure there are more elegant ways of doing this, and I understand that the subqueries can slow things down on large databases; however, I've returned 100's of records from my databases with just such a query (well, same concept) in just a blink of an eye.

5 5061
Seth Schrock
2,965 Expert 2GB
Try moving your WHERE clause to between lines 4 & 5. This would leave you with:

Expand|Select|Wrap|Line Numbers
  1. SELECT...
  2. FROM...
  3. WHERE...
  4. GROUP BY...
Sep 19 '12 #2
Tim F
16
Cheers for the reply!
I tried your suggestion but got error 'Cannot have aggregate function in WHERE clause (MAX()=)'
A little googling suggested I need to use HAVING instead of where so I ended up with:
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    tblProjects.Project_Number,
  3.    tblProjects.Project_Name,
  4.    tblProjectStatus.Exec_Status 
  5. FROM tblProjects
  6.    INNER JOIN tblProjectStatus 
  7.       ON tblProjects.Project_Number
  8.         tblProjectStatus.Project_Number
  9.    GROUP BY tblProjects.Project_Number
  10.    HAVING Date_Updated = 
  11.       MAX(SELECT 
  12.             Date_Updated 
  13.          FROM tblProjectStatus 
  14.          GROUP BY tblProjects.Project_Number 
  15.          HAVING tblProjectStatus.Project_Number =
  16.             tblProjects.Project_Number);
Which unfortunately produces 'cannot have aggregate function in expression (MAX()=)'

So it seems I might not be able to use MAX in this way - is there an alternative?
Sep 19 '12 #3
Seth Schrock
2,965 Expert 2GB
In your nested query, replace the HAVING with WHERE as the HAVING isn't needed. Unfortunately, I don't have a database that I can test this with, but that I what I'm reading from the error message. So your last line would be (broken down for easier reading):

Expand|Select|Wrap|Line Numbers
  1. HAVING Date_Updated = MAX(
  2. SELECT Date_Updated 
  3. FROM tblProjectStatus 
  4. GROUP BY tblProjects.Project_Number 
  5. WHERE tblProjectStatus.Project_Number = tblProjects.Project_Number
  6. );
Sep 19 '12 #4
zmbd
5,501 Expert Mod 4TB
The way I think of these queries is to break them up into small chunks:

Starting with table2:
What you want is the last (max) date of each entry made by the my id. So you need to group on the user ID and return the max date. Call this Q1
(myid,mydate) = (1,2/1/12) and (2,1/1/12)
SQL
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Table2.FK_MyID,
  3.    Max(Table2.MyDate) 
  4.       AS MaxOfMyDate
  5. FROM Table2
  6. GROUP BY Table2.FK_MyID;
This is great now we need the comment associated with these... well only two records will match so do a simple inner join with table2 against the agregate query Q1 on the FK_Myid and the MyDate fields. Show the fields from table 2 that we're interested in. Call this Q2
(PK_tbl2, FK_MyID, MYDate, Comment)=
(2, 1, 2/12/2012, Comment2)
(3, 2, 1/1/2012, Comment3)
SQL

Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Table2.PK_Tbl2, 
  3.    Table2.FK_MyID, 
  4.    Table2.MyDate, 
  5.    Table2.Comment
  6. FROM Table2 
  7.    INNER JOIN Q1 
  8.       ON (Table2.MyDate = Q1.MaxOfMyDate) 
  9.          AND (Table2.FK_MyID = Q1.FK_MyID);
Finally we need to get the names from table one... easy same inner join on table1 and q2 showing the name field from table1 and the date and comment from q2. Call this Q3
(Q2!PK_tbl2, Table1!MyName, Q2!MYDate, Q2!Comment)=
(2, Name1, 2/12/2012, Comment2)
(3, Name2, 1/1/2012, Comment3)

SQL -Q3:
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Q2.PK_Tbl2, 
  3.    Table1.MyName, 
  4.    Q2.MyDate,
  5.     Q2.Comment
  6. FROM Table1 
  7.    INNER JOIN Q2 
  8.       ON Table1.MyID = Q2.FK_MyID;
So the final SQL looks like:
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Q2.PK_Tbl2, 
  3.    Table1.MyName, 
  4.    Q2.MyDate,
  5.     Q2.Comment
  6. FROM Table1 
  7.    INNER JOIN 
  8.    ( SELECT 
  9.        Table2.PK_Tbl2, 
  10.        Table2.FK_MyID, 
  11.        Table2.MyDate, 
  12.        Table2.Comment
  13.     FROM Table2 
  14.        INNER JOIN
  15.           (SELECT 
  16.              Table2.FK_MyID,
  17.              Max(Table2.MyDate) 
  18.       AS MaxOfMyDate
  19.           FROM Table2
  20.           GROUP BY Table2.FK_MyID) 
  21.       AS Q1 
  22.           ON (Table2.MyDate = Q1.MaxOfMyDate) 
  23.              AND (Table2.FK_MyID = Q1.FK_MyID))
  24.     AS Q2 
  25.       ON Table1.MyID = Q2.FK_MyID;
-edit- found typo
Ofcourse, in Q2 you could go ahead and add in table1 to get the name value so you'd get something like:
Expand|Select|Wrap|Line Numbers
  1. SELECT 
  2.    Table2.PK_Tbl2, 
  3.    Table1.MyName, 
  4.    Table2.FK_MyID, 
  5.    Table2.MyDate, 
  6.    Table2.Comment
  7. FROM Table1 
  8.    INNER JOIN 
  9.       (Table2 
  10.          INNER JOIN
  11.          (SELECT 
  12.             Table2.FK_MyID,
  13.             Max(Table2.MyDate)
  14.                AS MaxOfMyDate
  15.           FROM Table2
  16.           GROUP BY Table2.FK_MyID)
  17.        AS Q1 
  18.        ON (Table2.MyDate = Q1.MaxOfMyDate) 
  19.           AND (Table2.FK_MyID = Q1.FK_MyID)) 
  20.       ON Table1.MyID = Table2.FK_MyID;
Which I think looks a little neater and one less sub.


Now I'm sure there are more elegant ways of doing this, and I understand that the subqueries can slow things down on large databases; however, I've returned 100's of records from my databases with just such a query (well, same concept) in just a blink of an eye.
Sep 19 '12 #5
Tim F
16
Thank you very much Seth & zmbd - I have followed your advice and learnt a bit in the process. I'm using zmbd's suggestion and following the logic have been able to make a few changes to get it doing exactly what I want.
Cheers!
Sep 19 '12 #6

Sign in to post your reply or Sign up for a free account.

Similar topics

3
by: Freelobly Li | last post by:
Hi all, I have encountered two problems when using linked tables; the linked table is connected to SQL server 2000. 1) How can I add the N prefix of a string constant in a query in order to...
0
by: Mike D | last post by:
now and again i've noticed that the Received field in a table linked from an Exchange server will have an invalid date. the invalid date always seems to be some day and some month in the year...
3
by: Michael Plant | last post by:
Hello one and all. I have a stored table in my database and the form I'm using is based on a query that draws data from my stored table and a linked table. The linked table is a *.txt file. ...
4
by: Shannan Casteel via AccessMonster.com | last post by:
I would like to be able to use 4 text boxes (i.e. Part #, Description, Quantity, Price) for up to 40 parts. However, only the Part # and Quantity will be entered. The Description and Price will...
24
by: Bob Alston | last post by:
Anyone know a way to make all access to a linked table, in another Access MDB, read only? I really don't want all the hassle of implementing full access security. I can't do this at the server...
4
by: Wayne Wengert | last post by:
I am trying to create a VB.NET Windows application to move some data from a local Access DB table to a table in a SQL Server. The approach I am trying is to open an OLEDB connection to the local...
22
by: RayPower | last post by:
I'm having problem with using DAO recordset to append record into a table and subsequent code to update other tables in a transaction. The MDB is Access 2000 with the latest service pack of JET 4....
11
by: AustinClark | last post by:
During login and logout, the workstations on my network dump some info into a text file. Part of this info is the current date and time, rendered by doing "echo %date%,%time%" at the command line. ...
7
by: nhkam | last post by:
I am using MS Access 2007 I have a transaction table which holds all records with posting date on each of them. I used a make table query to find out the max date hold in the transaction table and...
4
by: grego9 | last post by:
I have two tables that are linked by a common field called 'reference'. i am running a query and want the query to post a text of "EXCHANGE OV CHANGE" against each record where a field called "ORIG...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.