如何使用 JPA CriteriaQuery 自我离开加入根

How to self left join root using JPA CriteriaQuery

我正在尝试在同一个 table 上使用多个左连接,以将按严重程度划分的票证计数转置到列中。 所以我想知道是否可以将以下 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;