问题
I have a query as shown below;
SELECT
.
.
LISTAGG(DISTINCT CC.POPULATION, ', ') WITHIN GROUP (ORDER BY CC.POPULATION ASC),
.
.
FROM COUNTRY C
JOIN CITY CC ON C.ID = CC.COUNTRY_ID
--WHERE
GROUP BY C.ID;
I should be implement with querydsl for custom filtering and sorting operations but I got "No pattern found for LISTAGG" error
JPAQuery<Tuple> jpaQuery = jpaQueryFactory.select(
SQLExpressions.listagg(QCity.city.POPULATION, ",")
.withinGroup()
.orderBy(QCity.city.POPULATION.asc())
)
.from(QCountry.country)
.join(QCity.city).on(QCountry.country.id.eq(QCity.city.countryId))
//.where(custom filtering)
.groupBy(QCountry.country.id);
jpaQuery.fetch();
I try to add custom template like this but I couldn't succeed. Also my querydsl-sql version is 4.2.1
StringTemplate customPopulationTemplate = Expressions.stringTemplate(
"(LISTAGG(DISTINCT {0},',') WITHIN GROUP (ORDER BY {0} ASC))", QCity.city.population);
回答1:
Window functions are not included in the JPQL specification and as such not available in any JPA implementation. You could register these functions yourself using custom functions.
However, after this, these functions still won't be accessible in QueryDSL. You're stealing from the SQLExpressions
here to obtain a window expression. These methods live in SQLExpressions
for a reason: they only work with querydsl-sql
and not with querydsl-jpa
(again, because JPA itself does not support window functions). So after registering your custom function, you will still have to extend JPQLTemplates
to include the template for your custom window function.
You'd do this like this:
public class MyTemplates extends JPQLTemplates {
public MyTemplates() {
add(SQLOps.ROWNUMBER, "ROW_NUMBER({0})");
}
}
And then use it as follows:
new JPAQuery(entityManager, new MyTemplates()).from(entity).select(rowNumber())
Alternatively you could look into the blaze-persistence-querydsl extension, which has out of the box support for window functions (and many other features) for JPQL. For example:
QCat cat = QCat.cat;
BlazeJPAQuery<Tuple> query = new BlazeJPAQuery<Tuple>(entityManager, criteriaBuilderFactory).from(cat)
.select(cat.name, JPQLNextExpressions.rowNumber(), JPQLNextExpressions.lastValue(cat.name).over().partitionBy(cat.id));
List<Tuple> fetch = query.fetch();
来源:https://stackoverflow.com/questions/65378623/how-to-use-listagg-with-querydsl