如何使用JPA CriteriaQuery自左加入根

问题描述

我正在尝试在同一张表上使用多个左联接,以将凭单计数按严重性转换为列。 因此,我想知道是否可以将以下SQL查询编写为JPA CriteriaQuery:

select c.name,count(t) total,count(t0.id) as sev0,count(t1.id) as sev1,count(t2.id) as sev2
from tickets t
left join tickets t0 on t.id = t0.id and t0.severity = 0
left join tickets t1 on t.id = t1.id and t1.severity = 1
left join tickets t2 on t.id = t2.id and t2.severity = 2
inner join customers c on t.customer = c.id
group by c.name
order by c.name;

预期输出如下:

customer_name                    total  sev0  sev1  sev2
b1873f8bdcd4847e05ec942da3273bc0    1    1     0     0  
bc757dead99fb9658b1e42877f1febfb    20   3     5     12 
52793217b1f42c69e93df8eaf86f8db4    10   0     4     6  

我尝试使用多个根,这些根将冬眠变成了交叉联接,但后来不适用于我。

CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<CustomerDTO> query = cb.createquery(CustomerDTO.class);
Root<Ticket> tickets = query.from(Tickets.class);
Root<Ticket> sev0 = query.from(Ticket.class);
Root<Ticket> sev1 = query.from(Ticket.class);
Root<Ticket> sev2 = query.from(Ticket.class);
Join<Customer,Tickets> customer = query.join("customer_id");

Predicate sev0Condition = cb.and(cb.equal(tickets.get("id"),sev0.get("id")),cb.equal(sev0.get("severity"),cb.literal(0));
Predicate sev1Condition = cb.and(cb.equal(tickets.get("id"),sev1.get("id")),cb.equal(sev1.get("severity"),cb.literal(1));
Predicate sev2Condition = cb.and(cb.equal(tickets.get("id"),sev2.get("id")),cb.equal(sev2.get("severity"),cb.literal(2));

query.select(cb.construct(CustomerDTO.class,customer,cb.count(tickets.get("id"),cb.count(sev0.get("id"),cb.count(sev1.get("id"),cb.count(sev2.get("id")));
query.where(sev0Condition,sev1Condition,sev2Condition);
query.groupBy(customer);

List<CustomerDTO> customerList = session.createquery(query).getResultList();

解决方法

始终尝试避免自我加入。可以很容易地将此​​查询表述为不使用自身联接:

select c.name,count(*) total,count(case when t.severity = 0 then 1 else null end) as sev0,count(case when t.severity = 1 then 1 else null end) as sev1,count(case when t.severity = 2 then 1 else null end) as sev2
from tickets t
inner join customers c on t.customer = c.id
group by c.name
order by c.name;