I wrote this JPQL query and expect a result as List<Question>:
#Query("SELECT q FROM Question q WHERE q.id IN (SELECT qc.questions FROM QCard qc WHERE qc.id IN (SELECT ct.qCards FROM CTest ct WHERE ct.id=:id))")
These are my classes:
class CTest {
id, List<QCard>
}
class QCard{
id, List<Question>
}
class Question{
id
}
I expected all questions as return for given CTest.id.
But I got a compiler-error with message:
SQLSyntaxErrorException
I tried use ":" before "select" words but it had not helped.
What is wrong?
Test your SQL query in an SQL-client (e.g. Squirrel, DbVisualizer, etc.).
Assuming your foreign keys are named:
question_id in table QCard
card_id in table CTest
you could have an SQL with subselects like:
SELECT q.id
FROM Question q
WHERE q.id IN (
SELECT qc.question_id
FROM QCard qc
WHERE qc.id IN (
SELECT ct.card_id
FROM CTest ct
WHERE ct.id = 1 -- example test id
)
)
Does it return the expected result or are there syntax errors?
Then subsequently replace your subselects by JOINs.
Question and Cards
SELECT q.id, c.id
FROM Question q
JOIN QCard c ON c.question_id = q.id
Cards and Tests
SELECT c.id, t.id
FROM QCard c
JOIN CTest t ON t.card_id = c.id
All together
SELECT q.id, c.id, t.id
FROM Question q
JOIN QCard c ON c.question_id = q.id
JOIN CTest t ON t.card_id = c.id
Note: add WHERE clauses like WHERE t.id = 1 if needed.
Experiment with the FROM/JOIN order as it makes sense.
Then translate the running SQL query to JPQL. For example:
#Query("SELECT q"
+ " FROM CTest test"
// a test has many cards (1:n)
+ " JOIN QCard card ON card.id = test.card_id" // associated cards
// a card has many questions (1:n)
+ " JOIN Question q ON q.id = card.question_id" // associated questions
+ " WHERE test.id = :id")
public List<Question> findQuestionsByTestId(String id);
List<Question> findByIdIn(List<Long> idList); //In repository
or
String qlString = "select i from Item i where i.name IN :names";
Query q = em.createQuery(qlString, Item.class);
List<String> names = Arrays.asList("foo", "bar");
q.setParameter("names", names);
List<Item> actual = q.getResultList();
I did those example in my past work, check it, tnx
In your existing query, in inner queries you are selecting entities and checking IN against Id, which will definitely won't work. As you can't complete entry with the Id.
As you haven't shared your complete entity structure, assuming that you have two way relationship declared correctly in entities, here I am placing a reference query which uses the join:
#Query("SELECT q FROM Question q JOIN q.qCard qc WHERE q.qCardId = qc.id AND qc.cTestId = :id")
Where qCardId is the foreign key reference of QCard entity in Question entity and cTestId is the foreign key reference of CTest entity in QCard entity.
You can use this for your reference to update your query with joins.
Related
I want to write a complex hql query with relationships from 3 tables. It is necessary to make a selection of the selected columns so that they are located by ID
#Query("SELECT p.regId, p.method, p.tax, p.fee, p.netAmount, r.countSec, p.status " +
"FROM P p INNER JOIN R r INNER JOIN D d on p.regId = r.id AND p.regId = d.id")
List<P> findAllByRegId(String regId);
My compiler cannot execute the request, I don't understand what the problem is! Help, please
org.postgresql.util.PSQLException: ERROR: syntax error at or near "join"
The format for multiple joins is
SELECT columns ...
FROM table1 AS t1
INNER JOIN
table2 AS t2
ON t1.id = t2.id
INNER JOIN
table3 AS t3
ON t3.id = t1.id
Your join is totally wrong. You have to add ON keyword and map primary key and foreign key in first inner join.
Here is your join, which is wrong
SELECT columns FROM A a
INNER JOIN B b
INNER JOIN C c ON a.ColName = b.ColName AND a.ColName = c.ColName
Here is the correct syntex for multiple join
SELECT columns FROM A a
INNER JOIN B b ON a.ColName = b.ColName
INNER JOIN C c ON a.ColName = c.ColName
Here down is modified query
#Query("SELECT p.regId, p.method, p.tax, p.fee, p.netAmount, r.countSec, p.status " +
"FROM P p INNER JOIN R r ON p.regId = r.id INNER JOIN D d ON p.regId = d.id")
I have a table and a class marked as #Entity with
#Table(name="Employee")
It has two fields, Id and Name
i want to do left join on same table like,
Select t2.name, count(*)
from Employee t1 left join Employee t2 on t1.Id = t2.Id
where t1.Name = 'asd'
group by t2.Name
I had a workaround, I converted that query into sub query
Select EmployeeID From Employee
Where ManagerID in (Select EmployeeID where performance >= 4 )
And used DetachedCriteria and i got it worked. But this will reduce my performance. SO i will try your method and see if i can get it worked
Ref
https://forum.hibernate.org/viewtopic.php?p=2389790
I'm trying to write a jpql query to select the user with the most comments. If two users have the same number of comments I want to select both.
I tried this, something like this:
SELECT
c.user, COUNT(c.id) as commentCount
FROM
Comment c
WHERE
commentCount = (SELECT MAX(SIZE(user.comments)) FROM User user)
GROUP BY
c.user
and this:
SELECT
c.user
FROM
Comment c
GROUP BY
c.user
HAVING
COUNT(c) = (SELECT MAX(SIZE(user.comments)) FROM User user)
Neither approach works. What do I need to do here?
Here is a solution:
SELECT
u
FROM
User u
WHERE
u.comments.size = (SELECT MAX(u2.comments.size) FROM User u2)
This should work if you are using Oracle:
select u from User u where size(u.comments) = (
select max(count(c.id))
from User u2 inner join u2.comments c
group by u2.id
)
But MySQL and SQL Server do not support nested aggregate functions, max(count(c.id)) in this case. It is suggested to use a subquery, but with HQL you cannot have subqueries in a from clause. So I suggest you do this manually, i.e. load all users:
select u, size(u.comments)
from User u
and loop through the list.
For any others coming here and wanting to select a max(count()) in jpql and doesn't have an array, (like in the question the comments) take following jpql code into consideration:
select e.city
from Employees e
group by e.city
having count(e.id) >= All(select count(e) from Employees e group by e.city)
full example in a JPA Repository:
#Query(value = "select e.city from Employees e group by e.city " +
"having count(e.id) >= All(select count(e) from Employees e group by e.city)")
public List<Cities> findCityByMaxEmployeeCount();
I Have a non-entity class
public class CountryStatistics {
public CountryStatistics(Long numTowns, Long numVillages) {
...
}
}
For a given country i want to construct a statistics object.
Country, Village and City are the Entitys, so i tried things in line with code below.
String queryString =
"SELECT NEW mypackage.CountryStatistics(count(t), count(v))
FROM Town t, Village v WHERE t.country = :country AND v.country = :country"
TypedQuery<CountryStatistics> query =
em.createQuery(queryString ,CountryStatistics.class).setParameter("country", country);
query.getSingleResult()
Question: What is the correct way to count some entities in different tables in the same query?
With the above query i end up with way to high numbers if i put distinct like below, number of towns will be correct.
"SELECT NEW mypackage.CountryStatistics(count(distinct t), count(v))
FROM Town t, Village v WHERE t.country = :country AND v.country = :country"
But if I set it for villages also i get:
java.sql.SQLSyntaxErrorException: Multiple DISTINCT aggregates are not supported at this time.
The following query (not tested) should do what you want:
select count(distinct t.id), count(distinct v.id) from Country c
left join c.towns t
left join c.villages v
where c.id = :countryId
I'd like to start by apologizing for my unfamiliarity with Hibernate. I'm only recently getting into it and am far from an expert.
I have three tables: Contract, Products, and a link table between them to define a many to many relationship.
I'm trying to write an HQL query to return all contracts that contain a range of products. Unfortunately, the IN syntax works like an Any instead of an All. So if I want all contracts that have ProductA, ProductB, and ProductC, the IN keyword will return me contracts that have any individual one of those products, instead of contracts that have all of them.
How should I structure my HQL query?
Why are you expecting IN to behave like a AND? To my knowledge, IN is a kind of OR, not a AND. IN might thus not be what you're looking for. Have a look at Hibernate's Expressions and especially:
HQL functions that take collection-valued path expressions: size(), minelement(), maxelement(), minindex(), maxindex(), along with the special elements() and indices functions that can be quantified using some, all, exists, any, in.
[...]
The SQL functions any, some, all, exists, in are supported when passed the element or index set of a collection (elements and indices functions) or the result of a subquery (see below):
[...]
from Show show where 'fizard' in indices(show.acts)
For more than 2000 ids at in clause use a subquery like [from group where groupid in(select id from elemtable)]
Otherwise use criteria to overcome the stackoverflow error.
Example:
Session session = getHibernateTemplate().getSessionFactory().openSession();
Criteria criteriaEaquals = session.createCriteria(Elements.class);
criteriaEaquals.add(Restrictions.in("elementId", elemIds));
criteriaEaquals.setProjection(Projections.distinct(Projections.property("type")));
List list = criteriaEaquals.list();
session.close();
System.out.println("typelistis--->"+list.toString());
return list;
You can use group by / having:
select c
from Contract c join c.products p
where p.name in ('A', 'B', 'C')
group by c.id, // list ALL Contract properties
having count(*) = 3
Alternatively you can use a subquery to avoid listing all properties in group by:
from Contract c where c.id in (
select c.id
from Contract c join c.products p
where p.name in ('A', 'B', 'C')
group by c.id
having count(*) = 3
)
Obviously "3" will have to be replaced with the actual number of product names you supply in in clause.
In the blog I went over such hibernate queries, take a look at example #4.
Here is a snapshot (replace Articles with Contracts and Tags with Products):
String[] tags = {"Java", "Hibernate"};
String hql = "select a from Article a " +
"join a.tags t " +
"where t.name in (:tags) " +
"and a.id in (" +
"select a2.id " +
"from Article a2 " +
"join a2.tags t2 " +
"group by a2 " +
"having count(t2)=:tag_count) " +
"group by a " +
"having count(t)=:tag_count";
Query query = session.createQuery(hql);
query.setParameterList("tags", tags);
query.setInteger("tag_count", tags.length);
List<Article> articles = query.list();