Performing a LEFT OUTER JOIN using JPQL and JPA

Haven’t made a tutorial-type post in a while so here’s an installment of documenting something that should be already documented. The problem at hand is a very common one: how do you do a LEFT OUTER JOIN on two tables (entities) when you’re using the Java Persistence API.

Let’s go with the sports theme and model basketball shoe sponsorship. An NBA player may or may not have a shoe deal, for example Lebron James has a shoe deal with Nike while Juan Dixon doesn’t. We have two tables and entities to work with: Player and ShoeCompany. Now the task at hand is to retrieve all information about all players. Given that many of them don’t have shoe deals we want to be careful of not ignoring them in our query, that’s where the OUTER JOIN kicks in. In other words, retrieve the set of entities where matching values in the join condition may be absent. Here’s what the entities and tables look like:

@Entity
@Table( name="nba_player" )
public class Player {

    @Id @Column
    private Long id;

    @Column
    private String name;

    @OneToOne
    @JoinColumn( name="shoecompany_id" )
    private ShoeCompany shoeCompany;

    // getters and setters
}
@Entity
@Table( name="shoe_company" )
public class ShoeCompany {

    @Id @Column
    private Long id;

    @Column
    private String name;

    // getters and setters
}

Here’s what the tables look like:

nba_player(id, name, shoecompany_id)
shoe_company(id, name)

Doing this query without an OUTER JOIN is also possible, it’s quite simple actually, we just add an additional WHERE clause where we check for the foreign key being NULL.

SELECT *
FROM nba_player p, shoe_company s
WHERE p.shoecompany_id = s.id or p.shoecompany_id IS NULL

The same SQL query using an OUTER JOIN would look like:

SELECT *
FROM nba_player p LEFT OUTER JOIN  shoe_company s
                                       ON (p.shoecompany_id = s.id)

To generate the OUTER JOIN query using JPQL, you’ll have to write this:

SELECT p FROM Player p LEFT JOIN p.shoeCompany sc

That’s it, now you’re free to use and abuse LEFT OUTER JOINs all you want. I’m using TopLink Essentials as the JPA implementation but that shouldn’t come into play. Grab the techy part of the blog’s feed.

15 Comments

  1. Posted November 21, 2007 at 2:34 pm | Permalink

    Hi, nice example of left outer join. You write:

    …an installment of documenting something that should be already documented.

    I don’t know if you mean that it isn’t documented, because it is. Quite well, actually. In part 4.4.5.2 in the persistence part of the specifaction of EJB3.0. This is JSR-220.

  2. Verdeen
    Posted November 21, 2007 at 4:47 pm | Permalink

    Good example, the bridge from SQL to ORM query languages such as HQL and JPQL is often too confusing and the underlying SQL that is generated is vastly different from the actual query. There needs to be a reverse engineering tool from SQL to JPQL.

  3. 666snippets
    Posted November 21, 2007 at 9:18 pm | Permalink

    *searches JPQL tutorials*

  4. 666snippets
    Posted November 21, 2007 at 9:20 pm | Permalink

    looking at this increments my love for iBatis

  5. Posted November 21, 2007 at 10:55 pm | Permalink

    c4torcadomtr

  6. Jhoss
    Posted December 4, 2007 at 10:36 pm | Permalink

    Hi, I’m from Bolivia, and I want to know JPQL, a basic example… please…

  7. Mike
    Posted January 20, 2008 at 9:34 pm | Permalink

    Great Left Outer Join Example, Thank you!

  8. Nate
    Posted April 18, 2008 at 5:35 pm | Permalink

    Thank you for the easy to follow example. My situation, however, is a bit more complex. I’m joining on dates and in the first table, the date is represented as an integer (yyyyMMdd) and in the second, as a date field.

    I’ve tried everything including using the getter/setter methods to convert the Date to a Long and back, but I always get a “java.sql.SQLException: [SQL0401] Comparison operator = operands not compatible.” as the SQL it generates seems to be be comparing the data types as they’re stored in the database and I’m not sure how to get JPA/Toplink to do otherwise.

  9. Sanjeev Kulkarni
    Posted November 4, 2008 at 4:48 am | Permalink

    Thanks a lot…

  10. Michail
    Posted February 17, 2009 at 8:39 am | Permalink

    The author writes:

    This sql query:
    “SELECT * FROM nba_player p, shoe_company s WHERE p.shoecompany_id = s.id or p.shoecompany_id IS NULL”

    is the same as this sql query:
    “SELECT * FROM nba_player p LEFT OUTER JOIN shoe_company s ON (p.shoecompany_id = s.id)”.

    It is a mistake: the first query will repeat p (where shoecompany_id IS NULL) whith every company in show company dtable while the second query will generate only one record for such a player.

  11. Brandon
    Posted April 16, 2009 at 7:59 pm | Permalink

    Have you tried http://www.searchjava.org? Is a Google custom search to refine the search. I found great results…

  12. Salma Hanif
    Posted May 7, 2009 at 7:24 am | Permalink

    This example is not working.I need to implement ManyToOne. Can anyone help me in this ?

  13. Salma Hanif
    Posted May 7, 2009 at 7:26 am | Permalink

    org.hibernate.QueryException: could not resolve property: TicketStatus of: org.domain.supportadmin.entity.Tickets [select tList from org.domain.supportadmin.entity.Tickets tList join tList.TicketStatus tstatus where lower(tList.message) like '%%'or lower(tList.submitter) like '%%'or lower(tList.email) like '%%'or lower(tList.phone) like '%%'or lower(tList.owner) like '%%']

  14. Michel Ganguin
    Posted November 5, 2009 at 11:27 pm | Permalink

    Is it possible to make more complex joins with jpql? lets say there can be a hidden company:

    SELECT * FROM nba_player p LEFT OUTER JOIN shoe_company s ON (p.shoecompany_id = s.id AND s.name ‘hiddencompany’)

    but I still want to see all nba_player in the result, those with shoe_company ‘hiddencompany’ set to null.

    Is it possible to express this in jpql?

  15. Michel Ganguin
    Posted November 5, 2009 at 11:29 pm | Permalink

    I meant:
    SELECT * FROM nba_player p LEFT OUTER JOIN shoe_company s ON (p.shoecompany_id = s.id AND s.name <> ‘hiddencompany’)


2 Trackbacks/Pingbacks

  1. Performing a LEFT OUTER JOIN using JPQL and JPA

    [...]Haven’t made a tutorial-type post in a while so here’s an installment of documenting something that should be already documented. The problem at hand is s very common one: how do you do a LEFT OUTER JOIN on two tables (entities) when you’re …

  2. [...] [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*