JPA criteria query for PostgreSQL lateral join - java

I have a PostgreSQL query like following
select a.name, v.which, v.val, count(*) as cont
from table a left join lateral
(values ('ip', ip), ('port', port)
) v(which, val)
group by a.name, v.which, v.val
order by cont desc
limit 5;
I am trying to use hibernate criteriabuilder to construct this query but don't know what to do for the left join lateral part. Can anybody help ?
So far I have :
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createquery();
Root<table> tableRoot = criteriaQuery.from(table.class);
How to specify left join lateral type here ? and group by fields v.which, v.val ?

Related

How to join an entity with custom select using CriteriaBuilder

I have a scenario where I need to get the row with maximum date. The SQL query for this would be
SELECT c.*
FROM course c
INNER JOIN
(SELECT moduleId ,MAX(endDate) AS max_date
FROM course
WHERE moduleId = 12345
GROUP BY moduleId
) customSelect
ON customSelect.moduleId = c.moduleId AND c.endDate = customSelect.max_date
WHERE c.moduleId = 12345
I need to convert this query to JPA using CriteriaBuilder.Since this isn't a direct entity join, rather a selection join to root entity, I'm having trouble to figure out how to join the custom select part to the root entity Course with below syntax:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Course> criteriaQuery = builder.createQuery(Course.class);
Root<Course> root = criteriaQuery.from(Course.class);
And then how to root.join(JoinType.INNER) to join customSelect part?
If someone can show some pointers to the syntax of of joining the root to a custom selection, that would be great.
Try this
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Course> criteriaQuery = builder.createQuery(Course.class);
Root<Course> root = criteriaQuery.from(Course.class);
criteriaQuery.select(root).where(cb.equal(root.get(Course_.moduleId), 12345));
criteriaQuery.orderBy(cb.desc(r.get(Course_.endDate)));
TypedQuery<Course> query = em.createQuery(criteriaQuery);
query.setMaxResult(1);
Course result = query.getSingleResult();

How to add filter on second table parameter while doing left join using criteriaquery

I am stuck in a situation where I am not able to create a filter on left join between two table.
My query is something like this.
select count(*)
from orders o
left
join payments p
on o.id = p.o_id
where o.uid_id = 1
and p.name = "abc"
I am trying to do left join using criteria query. In criteria query.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Orders> query = cb.createQuery(Orders.class);
Root<Orders> ordersRoot = query.from(Orders.class);
Join<Orders, Payments> join = ordersRoot.join(JOIN_COLUMN, JoinType.LEFT);
List<Predicate> predicates = new ArrayList<>();
predicates.addAll(getPredicates(cb, ordersRoot)); //this method gives other predicates on order table
query.where(predicates.toArray(new Predicate[predicates.size()]));
query.select(ordersRoot).distinct(true);
TypedQuery<Orders> query = entityManager.createQuery(criteriaQuery);
List<Orders> list = query.getResultList();
This is my criteria Java code.
In this I have not added for this check.
orders and payments table has one to many relationship.

JPA Criteria Query for Left joins

I am new to JPA and I have a Left Join scenario.
I have my native sql query as below and I am using left join to fetch the complete records from V_MONITORING table for st.id = 10001.
I have some null values for id_legislature which also needs to be selected and hence using a left join
select distinct
mv.id_set, mv.id_travel, mv.id_legislature
from
V_MONITORING mv
left join v_set st on mv.id_set = st.id
left join v_travel fg on mv.id_travel = fg.id
left join v_legislature gg on mv.id_legislature = gg.id;
The same thing I am implementing using the JPA criteria query, I am unable to fetch the null records
Below is the code
Predicate predicate = cb.conjunction();
Root<MonitoringBE> mvRoot = criteriaQuery.from(MonitoringBE.class);
mvRoot.fetch(MonitoringBE.id_set, JoinType.LEFT);
mvRoot.fetch(MonitoringBE.id_travel, JoinType.LEFT);
mvRoot.fetch(MonitoringBE.id_legislature, JoinType.LEFT);
final Path<Object> serieneinsatzterminPath= mvRoot.get(MonitoringBE.id_set);
predicate = cb.and(predicate, cb.EqualTo(serieneinsatzterminPath.get(SetBE.GUELTIG_VON_DATUM), startSetDate));
criteriaQuery.multiselect(
mvRoot.get(MonitoringBE.id_travel).alias("id_travel"),
mvRoot.get(MonitoringBE.id_set).alias("id_set"),
mvRoot.get(MonitoringBE.id_legislature).alias("id_legislature"))
.distinct(true).where(predicate);
Can some one guide me.
You have to replace the mvRoot.get(MonitoringBE.id_travel) and others in the multiselect-statement with mvRoot.join(MonitoringBE.id_travel, JoinType.LEFT). Otherwise they will end up in a inner join.

Criteria API count from grouped count

I have a problem with Criteria API (JPA 2.0). I want to write code which returns the same result as query (select count from (select count from ... group by ...)):
SELECT COUNT(*) FROM (
SELECT COUNT(*) FROM a
LEFT JOIN p ON a.id = p.a_id
LEFT JOIN s ON a.id = s.a_id
WHERE ... GROUP BY s.r_id
)
I wrote something like this:
CriteriaBuilder builder = slave.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(Long.class);
Subquery<Long> subquery = query.subquery(Long.class);
Root<A> entity = subquery.from(A.class);
Join<A, P> pJoin = entity.join("p", JoinType.LEFT);
Join<A, S> sJoin = entity.join("s", JoinType.LEFT);
subquery.select(builder.count(entity));
subquery.where(/*where predicate*/);
subquery.groupBy(sJoin.get("r"));
query.select(builder.count(subquery));
Long result = slave.createQuery(query).getSingleResult();
But I get the exception:
java.lang.IllegalStateException: No criteria query roots were specified
What am I doing wrong here?

Order by fetch join attribute

I have a criteriaQuery
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<School> criteriaQuery = builder.createQuery(School.class);
Root root = criteriaQuery.from(EducationDistrictBundle.class);
criteriaQuery.distinct(true);
Join join = root.join("schoolList",JoinType.LEFT);
join.fetch("address", JoinType.LEFT);
criteriaQuery.select(join);
adding predicates and ordering
criteriaQuery = criteriaQuery.where(builder.and(predicates.toArray(new Predicate[predicates.size()])));
criteriaQuery.orderBy(builder.desc(join.get("address").get("fullAddress")));
SQL query looks like this
SELECT DISTINCT
school2_.id AS id1_52_0_,
address3_.id AS id1_1_1_,
school2_.createdTs AS createdT2_52_0_,
school2_.guid AS guid3_52_0_,
school2_.updatedTs AS updatedT4_52_0_,
school2_.version AS version5_52_0_,
school2_.accreditation AS accredit6_52_0_,
school2_."address_id" AS address14_52_0_,
school2_."belonging_id" AS belongi15_52_0_,
school2_.director AS director7_52_0_,
school2_."financialType_id" AS financi16_52_0_,
school2_.fullName AS fullName8_52_0_,
school2_.license AS license9_52_0_,
school2_.number AS number10_52_0_,
school2_.parent_id AS parent_17_52_0_,
school2_.school AS school11_52_0_,
school2_.shortName AS shortNa12_52_0_,
school2_.site AS site13_52_0_,
school2_."subordinationType_id" AS subordi18_52_0_,
school2_."type_id" AS type_id19_52_0_,
address3_.createdTs AS createdT2_1_1_,
address3_.guid AS guid3_1_1_,
address3_.updatedTs AS updatedT4_1_1_,
address3_.version AS version5_1_1_,
address3_.addressUID AS addressU6_1_1_,
address3_.fullAddress AS fullAddr7_1_1_,
address3_.fullHouse AS fullHous8_1_1_,
address3_.houseUID AS houseUID9_1_1_,
address3_.oktmo_id AS oktmo_i12_1_1_,
address3_.plain AS plain10_1_1_,
address3_.postalCode AS postalC11_1_1_,
address3_1_.flat AS flat1_0_1_,
address3_1_.type AS type2_0_1_,
CASE WHEN address3_1_."id" IS NOT NULL THEN 1
WHEN address3_.id IS NOT NULL THEN 0 END AS clazz_1_
FROM "education_district_bundle" educationd0_ LEFT OUTER JOIN "education_district_bundle_school" schoollist1_
ON educationd0_.id = schoollist1_."education_district_bundle_id"
LEFT OUTER JOIN "school" school2_ ON schoollist1_."schoolList_id" = school2_.id
LEFT OUTER JOIN "address" address3_ ON school2_."address_id" = address3_.id
LEFT OUTER JOIN "address_refine" address3_1_ ON address3_.id = address3_1_."id"
CROSS JOIN "address" address4_
WHERE school2_."address_id" = address4_.id AND educationd0_."educationDistrict_id" = 179
ORDER BY address4_.fullAddress DESC
And i have an exception
PSQLException: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
But why there was generated cross join "address4"? I just want to order like this
ORDER BY address3_.fullAddress DESC
if i'm ordering by school.name
order by school2_.shortName asc
there is no another cross join for school...
Even if Fetch is not a Join type, you can cast it.
You need to have the joins defined up-front, to avoid joining the same association twice
Since you need those two additional joins for the "orderBy" clause you can use INNER instead of LEFT:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<School> criteriaQuery = builder.createQuery(School.class);
Root root = criteriaQuery.from(EducationDistrictBundle.class);
criteriaQuery.distinct(true);
Join schoolJoin = root.join("schoolList", JoinType.LEFT);
Join addressJoin = ((Join) schoolJoin.fetch("address", JoinType.INNER));
Join fullAddressJoin = addressJoin.fetch("fullAddress", JoinType.INNER);
criteriaQuery = criteriaQuery.where(builder.and(predicates.toArray(new Predicate[predicates.size()])));
criteriaQuery.orderBy(builder.desc(fullAddressJoin));
criteriaQuery.select(schoolJoin);

Categories

Resources