0

I've reviewed multiple Q&A involving TOP 1 and CROSS APPLY (including the very informative 2043259), but I still can't figure out how to solve my issue. If I had a single join I'd be fine, but fitting TOP 1 into the middle of a chain of joins has stumped me.

I have four tables and one of the tables contains multiple matches when joining due to a previous bug (since fixed) that created new records in the table instead of updating existing records. In all cases, where there are multiple records, it is the top-most record that I want to use in one of my joins. I don't have access to the table to clean up the extraneous data, so I just have to deal with it.

The purpose of my query is to return a list of all "Buildings" managed by a particular person (user choses a person's name and they get back a list of all buildings managed by that person). My tables are:

Building (a list of all buildings):

BuildingId  BuildingName
1           Oak Tree Lane
2           Lighthoue Court
3           Fairview Lane
4           Starview Heights

WebBuildingMapping (mapping of BuidingId from Building table, that is part of an old system, and corresponding WebBuildingId in another piece of software):

BuildingId  WebBuildingId
1           201
2           202
3           203
4           204

WebBuildingContacts (list of ContactID for the building manager of each building). This is the table with duplicate values - where I want to choose the TOP 1. In sample data below, there are two references to WebBuidingId = 203 (row 3 & row 5) - I only want to use row 3 data in my join.

Id  WebBuildingId   ContactId
1   201             1301
2   202             1301
3   203             1303
4   204             1302
5   203             1302

Contacts (list of ContactIds and corresponding property manager Names)

ContactId   FullName
1301        John
1302        Mike
1303        Judy

As noted, in the example above, the table WebBuildingContact has two entries for the building with a WebBuidingId = 203 (row 3 and row 5). In my query, I want to select the top one (row 3).

My original query for a list of buildings managed by 'Mike' is:

SELECT BuildingName
FROM Building bu 
JOIN WebBuildingMapping wbm ON wbm.BuildingId = bu.BuildingId
JOIN WebBuildingContact wbc ON wbc.WebBuildingId = wbm.WebBuildingId
JOIN Contacts co ON co.ContactId = wbc.ContactId
WHERE co.FullName = 'Mike'

This returns 'Fairview Lane' and 'Starview Heights'; however, Judy manages 'Fairview Lane' (she's the top entry in the WebBuildingContacts table). To modify the query and eliminate row 5 in WebBuildingContacts from the join, I did the following:

SELECT BuildingName
FROM Building bu 
JOIN WebBuildingMapping wbm ON wbm.BuildingId = bu.BuildingId
JOIN WebBuildingContact wbc ON wbc.WebBuildingId = 
    (
    SELECT TOP 1 WebBuildingId
    FROM WebBuildingContact
    WHERE WebBuildingContact.WebBuildingId = wbm.WebBuildingId
    )
JOIN Contacts co ON co.ContactId = wbc.ContactId
WHERE co.FullName = 'Mike'

When I try this; however, I get the same result set (ie it returns 'Mike' as manager for 2 buildings). I've also made various attempts to use CROSS APPLY but I just end up with 'The multi-part identifier could not be bound', which is a whole other rabbit hole to go down.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83

1 Answers1

0

You could try this:

SELECT bu2.BuildingName
FROM building bu2
WHERE bu2.BuildingId IN 
    (SELECT MAX(bu.BuildingId)
    FROM Building bu 
    JOIN WebBuildingMapping wbm ON wbm.BuildingId = bu.BuildingId
    JOIN WebBuildingContact wbc ON wbc.WebBuildingId = wbm.WebBuildingId
    JOIN Contacts co ON co.ContactId = wbc.ContactId
    WHERE co.FullName = 'Mike'
    );
  • Thank you Yenny - that worked great! Just to help my learning, if anyone has a way that this can be done using either TOP 1 or CROSS APPLY I'd still be interested in seeing it. – AvgSizedHead Jan 19 '22 at 18:28