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
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.
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.
*searches JPQL tutorials*
looking at this increments my love for iBatis
c4torcadomtr
Hi, I’m from Bolivia, and I want to know JPQL, a basic example… please…
Great Left Outer Join Example, Thank you!
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.
Thanks a lot…
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.
Have you tried http://www.searchjava.org? Is a Google custom search to refine the search. I found great results…
This example is not working.I need to implement ManyToOne. Can anyone help me in this ?
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 '%%']
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?
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
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 …
[...] [...]