简体   繁体   中英

Multiple table join with condition on second table

There are two tables: person and invoice there are many invoice rows for each person, and I want select all persons info with last invoice amount of them.

Person

code  |  Name | ....
1     |  name1
2     |  name1
3     |  name1

Invoice

ID    | person_code   |  amount   |  date 
1     |  2            |  30000    |  12
2     |  1            |  40000    |  10
3     |  3            |  50000    |  12
4     |  2            |  60000    |  14
5     |  3            |  70000    |  12
6     |  2            |  80000    |  12
7     |  1            |  90000    |  18

I want select

person code | person name  | last amount
1           |  name1       |  90000
2           |  name2       |  60000
3           |  name3       |  70000

or

 SELECT person.code , person.name , lastinvoice.amount 
 FROM person 
 LEFT JOIN
     (SELECT * FROM invoice where invoice.person_code=person.code order by date, ID) as
 lastinvoice ON lastinvoice.person_code = person.code

This query does not work on ms access:

select * from invoice as i where id=(select max(id) from invoice where personCode=i.personcode and date=( select max(date) from invoice where personCode=i.PersonCode

You can do

SELECT p.code, p.name, i.amount
FROM person p
INNER JOIN invoice i on i.person_code = p.code AND i.date = 
  (SELECT MAX(date) FROM invoice WHERE person_code = p.code)
AND i.ID = (SELECT MAX(ID) FROM invoice where person_code = p.code AND ID = i.ID)

I've tested this, and it works fine!

Since there can be multiple payments for the same person, on the same date, you need a way to break the tie to find the latest payment. While not great.. you could use the ID column (autonumber). However, that requires an additional query: one to get the max date and another to get the max ID for that date.

SELECT p.code, i.[Date], i.amount
FROM   Person p INNER  JOIN 
    (  Invoice i INNER JOIN
          (
              SELECT MAX(mxi.ID) AS MaxID, mxi.person_code, mxd.latestDate
              FROM  Invoice mxi INNER JOIN 
                       (
                          SELECT person_code, MAX([Date]) AS LatestDate
                          FROM   Invoice
                          GROUP BY person_code
                        ) mxd ON mxd.person_code = mxi.person_code AND mxd.latestDate = mxi.[Date]
              GROUP BY  mxi.person_code, mxd.latestDate
           )  lt ON lt.MaxID = i.ID
     ) ON p.code = i.person_code

Now for the problem. The query above works until you change the first join from INNER to LEFT . Then Access complains it is too complex/ambiguous. (Maybe someone more familiar with Access could rewrite it to satisfy its limitations.) Otherwise, you may have to split part of the sql into a view/stored query. Then JOIN to the view/stored query. Like I said.. it often gets convoluted. But it is the only way I can think of to make Access happy.

vLatestInvoice (Stored Query/View)

SELECT i.ID, i.person_code,  i.[Date], i.amount
FROM   Invoice AS i INNER JOIN 
         (   SELECT MAX(mxi.ID) AS MaxID, mxi.person_code, mxd.latestDate
             FROM  Invoice mxi INNER JOIN 
                      (
                         SELECT person_code, MAX([Date]) AS LatestDate
                         FROM   Invoice
                         GROUP BY person_code
                      ) mxd ON mxd.person_code = mxi.person_code AND mxd.latestDate = mxi.[Date]
             GROUP BY  mxi.person_code, mxd.latestDate
         ) AS lt ON lt.MaxID = i.ID;

Main Query:

SELECT p.code, l.[Date], l.amount
FROM Person p LEFT JOIN vLatestInvoice l ON l.person_code = p.code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM