These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Problem translating SQL joins to HQL-with-joins
PostPosted: Tue Mar 17, 2009 12:39 pm 
Newbie

Joined: Wed Oct 29, 2008 6:38 am
Posts: 2
Hibernate version: 3.2.6

Name and version of the database you are using: MSSQL 2000

Hi everyone,

I have a problem with a SQL query that itself is rather simple, but I can't translate it to HQL.
The data-model is as follows: I have the entities F, P, A and FA.
F:P is a one-to-many-relationship, P:A is a one-to-one relationship (optional) and A:FA is a many-to-many-relationship (using a join table named A_FA).

The goal is to get all Fs (meeting certain criteria) and all associated P that have an A that has some certain FAs associated. If no such P to a given F exists, leave it out in the result (nullify it), but gimme that F!

So my SQL looks like this:
Code:
select F.id, F.name, P.someThing
from F
   left join P
      inner join A
         on P.id = A.p_id
         and exists (
            select *
            from A_FA
               inner join A on A_FA.a_id = a.id
            where A_FA.fa_id in (183, 199) and A.p_id = P.id
         )
      on P.f_id = f.id
where F.id in (...)


It is basically a left join into an inner join using a subselect.

I simlpy can't get it to work with hibernate.
The mapped classes are:
Code:
class F {
   @OneToMany(mappedBy = "f")
   public Set<P> getPs() {...}
}
class P {
   @ManyToOne
   @JoinColumn(name = "f_id")
   public F getF() {...}
   @OneToOne(mappedBy="p", optional=true)
   public A getA() {...}
}
class A {
   @OneToOne(optional=false)
   @JoinColumn(name="p_id", unique=true)
   public P getP() {...}
   @ManyToMany
   @JoinTable(name="A_FA",
      joinColumns={@JoinColumn(name="a_id")},
      inverseJoinColumns {@JoinColumn(name="fa_id")})
   public Set<FA> getFAs() {...}
}
class FA {
   // no associations here, just a few data fields
}


My first HQL-approaches either returned too many rows (the outer join was a little bit too outer) or too few (some inner join condition reduced the number of rows).

Basically the problem seems to be the outer join into an inner join. I transformed the SQL to use a subquery in the from-clause (select ... from F left join (select .. from P inner join ...) wich works of course, but is as in-translatable to HQL as far as I know.

I tried to use the with-keyword in my HQL queries - nothing worked. e.g.

Quote:
org.hibernate.hql.ast.InvalidWithClauseException: with clause can only reference columns in the driving table [select f.id, f, p from a.b.c.F f left join f.ps p with (p in (select a.p from a.b.c.A a inner join a.fas fa where fa.id in (:attribute))) where f.id in (:ids)]


I searched the forums and found another post that contained a link to a bug report regarding the with-clause
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2772 that suggests another syntax (in my case that would mean to use p.id instead of p), but, you might have guessed, that doesn't work either:

Quote:
org.hibernate.hql.ast.QuerySyntaxException: with-clause referenced two different from-clause elements [select ... with (p.id in (select a.p.id from ...]


I've no idea what to do about this :( Any help is appreciated! (Side-note: Hibernate is used as a JPA provider).

Thanks
-markus


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 17, 2009 2:24 pm 
Beginner
Beginner

Joined: Wed Nov 19, 2008 8:25 am
Posts: 46
Location: Saint Petersburg, Russian Federation
Try the following approach:

Code:
List list = session.createQuery("from F f left join f.ps p left join p.a a left join a.FAs fa with fa.id in (:fa_ids) where f.id in (:f_ids)")
    .setParameterList("fa_ids", Arrays.asList(183L, 199L))
    .setParameterList("f_ids", Arrays.asList(1L, 4L))
    .list();


Please not that the SQL produced by the given HQL (as well as original native SQL) is quite ineffective.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 18, 2009 3:53 am 
Newbie

Joined: Wed Oct 29, 2008 6:38 am
Posts: 2
Thanks denis for the comments.

denis.zhdanov wrote:
Try the following approach:

Code:
List list = session.createQuery("from F f left join f.ps p left join p.a a left join a.FAs fa with fa.id in (:fa_ids) where f.id in (:f_ids)")
    .setParameterList("fa_ids", Arrays.asList(183L, 199L))
    .setParameterList("f_ids", Arrays.asList(1L, 4L))
    .list();



Yeah, this is actually much simpler than my first approaches (and I feel a little dumb now), but it isn't semantically correct. The problem here is that if I e.g. have a F with id 1 and two associated Ps where each P has its A and only one of the two As has an FA with id 183, I get two lines in the result set with F.id == 1. But it ought to only return one.

The resulting SQL looks something like this:

Code:
select F.id, F.name, ...
from F
   left outer join P on P.f_id = F.id
   left outer join A on A.p_id = P.id
   left outer join A_FA on A_FA.a_id = A.id
   left outer join FA on A_FA.id = FA.id and FA.id in (...)
where F.id in (...)


And the cause is obvious: Even if a P has no A, the given P is returned in the result. But I want all Fs associated with only the Ps whose A has at least one of the desired FAs... in SQL this is again easily achievable:

Code:
select F.id, F.name, ...
from F
   left outer join P
      inner join A on A.p_id = P.id
      inner join ... inner join ...
      inner join FA on A_FA.id =FA.id and FA.id in (...)
   on P.f_id = F.id
where F.id in (...)


Using a left join into inner joins and reordering the joins produces the desired result. (The join to FA is not actually necessary, but does no harm.) Is that somehow possible using HQL?

denis.zhdanov wrote:
Please not that the SQL produced by the given HQL (as well as original native SQL) is quite ineffective.


Yes, I noticed that now. Thanks for bringing up this much easier native SQL :)

-markus


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.