2011-08-04 1 views
9

J'essaie d'obtenir une moyenne pour un compte sur un groupe en joignant une sous-requête. Je ne sais pas si c'est la bonne façon d'y aller mais je ne pourrais rien faire à propos des sous-requêtes autres que la doc mysema.JPQL/QueryDSL: joindre la sous-requête et obtenir une colonne d'alias

Scénario: Combien de commandes par produit un client a-t-il effectuées en moyenne? Signification: Un client commande des produits. Ainsi, un client a commandé un produit spécifique un certain nombre de fois (compte). Quel est le nombre moyen de commandes passées par le client pour un produit? Cela peut sembler un peu hypothétique, en fait, c'est juste une partie d'un prototype, mais je me suis demandé comment obtenir une référence à une colonne personnalisée créée dans une sous-requête avec la QueryDSL de Mysema.

Dans SQL, vous donnez simplement un alias à la colonne count et vous vous connectez en utilisant une seconde colonne ID. QueryDSL a aussi la méthode "as()" mais je n'ai aucune idée, comment récupérer cette colonne et je ne vois pas comment il peut rejoindre une requête avec d'autres, puisque query.list() reçoit juste une liste mais pour certains raison pour laquelle la jointure l'accepte. Se sent mal ...

Voici mon code:

JPQLQuery query = createJPQLQuery(); 

    QOrdering qOrdering = QOrdering.ordering; 
    QProduct qProduct = QProduct.product; 
    QCustomer qCustomer = QCustomer.customer;   

    // how many of each product did a customer order? 
    HibernateSubQuery subQuery = new HibernateSubQuery(); 
    subQuery.from(qOrdering).innerJoin(qOrdering.product,qProduct).innerJoin(qOrdering.customer, qCustomer); 
    subQuery.groupBy(qCustomer,qProduct).list(qCustomer.id,qProduct.id,qProduct.count()); 

    // get the average number of orders per product for each customer 
    query.from(qCustomer);  
    query.innerJoin(subQuery.list(qCustomer.id,qOrdering.count().as("count_orders")));  
    query.groupBy(qCustomer.id); 
    return (List<Object[]>) query.list(qCustomer.firstname,subQuery.count_orders.avg()); 

Encore une fois: Comment puis-je me joins à une sous-requête? Comment puis-je obtenir la colonne "count" alias pour faire plus d'agrégation comme avg (mon groupe est-il juste?) Peut-être que j'ai d'autres erreurs, donc toute aide appréciée!

Merci!

Edit: C'est une sorte de SQL natif, je voudrais voir des produits QueryDSL:

Select avg(numOrders) as average, cust.lastname from 
customer cust 
inner join 
(select count(o.product_id) as numOrders, c.id as cid, p.name 
from ordering o 
inner join product p on o.product_id=p.id 
inner join customer c on o.customer_id=c.id 
group by o.customer_id, o.product_id) as numprods 
on cust.id = numprods.cid 
group by numprods.cid 
order by cust.lastname; 

Répondre

11

En utilisant la jointure des sous-requêtes dans la clause n'est pas autorisé. en JPQL, les sous-requêtes ne sont autorisées que dans les parties WHERE et HAVING. Les signatures de méthode de jointure dans les requêtes QueryDSl JPA sont trop larges.

Comme cette requête nécessite deux niveaux de regroupement, elle ne peut peut-être pas être exprimée avec JPQL/Querydsl JPA.

Je suggère d'écrire cette requête en utilisant le support de requête QueryDSl JPA Native.

Comme Querydsl JPA utilise JPQL en interne, il est limité par l'expressivité de JPQL.

+0

Merci! Dommage cependant, comme je pense à construire une recherche générique basée sur QueryDSL et tout moyen de limitation théorique, je dois réfléchir à la façon d'inclure des techniques alternatives dans mon balisage de recherche ... – Pete

+0

Bien qu'à la réflexion: Comment puis-je accéder? cette colonne count() aliasée? – Pete

+0

Pour la colonne de comptage d'alias, utilisez à la place une instance Path (Path alias, subQuery.as (alias), puis utilisez l'alias par la suite) –

Questions connexes