MS Access LEFT JOIN : Join expression not supported

Posts   
 
    
rdhatch
User
Posts: 198
Joined: 03-Nov-2007
# Posted on: 31-Jan-2008 10:32:13   

Frans & Company...

Problem: Experiencing bug when working with Access. Access will throw an error "Join expression not supported" when doing:

FROM table1
INNER JOIN table2
    ON table2.x = table1.x

LEFT JOIN table3
    ON table3.x = table2.x
    AND table3.x = table1.x

Access will only let one table be used in the JOIN syntax. Really, this is an Access limitation. However, it is a problem. I was writing code like this to pass to a TypedListDAO:

Dim myRelation As EntityRelation = TierEntity.Relations.FixedCostEntityUsingTierId

'Special Left Join Filters
Dim myFixedCostFilter As New PredicateExpression
myFixedCostFilter.Add(PlanFields.BenefitId = FixedCostFields.BenefitId)
myFixedCostFilter.Add(PlanFields.NetworkId = FixedCostFields.NetworkId)

'Filter left join by an additional field on another table
myRelation.CustomFilter = myFixedCostFilter

'Special Join on Fixed Costs
myRelations.Add(myRelation, "", "", JoinHint.Left)

Solution: I did, however, come up with a solid solution... and I thought it would be helpful others. Although, I would prefer if the above code actually worked.

The key is to add your Left Join Filters to the WHERE clause... and make sure that your filters always match.

SQL we will generate:

WHERE (fixedcost.id IS NULL) OR (fixedcost.id IS NOT NULL AND (__myLeftJoinPredicates___) )

Creating WHERE Clause - Very Clean

'Special Left Join Filters
Dim myFixedCostFilter As New PredicateExpression
myFixedCostFilter.Add(PlanFields.BenefitId = FixedCostFields.BenefitId)
myFixedCostFilter.Add(PlanFields.NetworkId = FixedCostFields.NetworkId)

Dim myWhereClause as PredicateExpression = Util.getLeftJoinWHEREClause(New FixedCostEntity, myFixedCostFilter)

Function to Build Proper Predicate


Public Shared Function getLeftJoinWHEREClause(Of TEntity As {IEntity, EntityBase})(ByRef myLeftJoinEntity As TEntity, ByRef myLeftJoinFilters As PredicateExpression) As PredicateExpression
    'Cannot do a LEFT JOIN ON x AND y when x and y are in different tables.
    'The ON clause can only accept logic related to the join. 

    'RYAN'S SOLUTION: make the WHERE clause match both ways

    'WHERE (fixedcost.id IS NULL) OR (fixedcost.id IS NOT NULL AND (__myPredicates___) )

    Dim myFilter As New PredicateExpression

    'Need a Primary Key field to determine if the record is blank or not
    Dim myKey As EntityField = DirectCast(myLeftJoinEntity.PrimaryKeyFields(0), EntityField)

    'IS NULL
    myFilter.Add(myKey = System.DBNull.Value)

    'NOT NULL
    Dim myExistsFilter As New PredicateExpression
    myExistsFilter.Add(myKey <> System.DBNull.Value)
    myExistsFilter.AddWithAnd(myLeftJoinFilters)

    'Combine IS NULL OR NOT NULL
    myFilter.AddWithOr(myExistsFilter)

    Return myFilter
End Function

Hope this helps someone. I do, however, wish LLBLGen would do this automatically for EntityRelation.CustomFilter when working with Access.

Thank you,

Ryan D. Hatch

Walaa avatar
Walaa
Support Team
Posts: 14952
Joined: 21-Aug-2005
# Posted on: 31-Jan-2008 10:36:05   

Thanks for the suggestion, we'll check it out.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39620
Joined: 17-Aug-2003
# Posted on: 31-Jan-2008 12:35:33   

How did you get the non-ansi join in the access filter? It should always use ansi outer joins/inner join statements. So I fail to see how you got 'table1, table2' in the FROM clause, could you elaborate on that a bit?

Frans Bouma | Lead developer LLBLGen Pro
rdhatch
User
Posts: 198
Joined: 03-Nov-2007
# Posted on: 31-Jan-2008 16:39:40   

Otis wrote:

How did you get the non-ansi join in the access filter? It should always use ansi outer joins/inner join statements. So I fail to see how you got 'table1, table2' in the FROM clause, could you elaborate on that a bit?

Hi Frans, Sorry about that. table1 / table2 join syntax wasn't correct... I just typed it in (and fixed it in my post).

The join syntax that causes the problem is the AND clause in the LEFT JOIN - which is filtering using a table not mentioned in the ON clause.

I had to move "AND table3.x = table1.x" into the WHERE clause. Because this is a LEFT JOIN and we want all records to show up - I also had to wrap this in a NULL test. So the end result is: "WHERE (table3.x IS NULL) OR (table3.x IS NOT NULL AND (table3.x = table1.x))".

Ryan

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39620
Joined: 17-Aug-2003
# Posted on: 03-Feb-2008 10:52:21   

Ok, thanks for the information. It's not possible to do access specific things in the relationcollection, so I'll add a remark to the documentation about this.

Frans Bouma | Lead developer LLBLGen Pro