Using JPA Criteria API, I want to group by a column and join the values of another column.
For example, the below is the sql approach and I am looking for the equivalent criteria query (and jpql query) approach.
mysql> select *from GroupConcatenateDemo;
+------+-------+
| Id | Name |
+------+-------+
| 10 | Larry |
| 11 | Mike |
| 12 | John |
| 10 | Elon |
| 10 | Bob |
| 11 | Sam |
+------+-------+
GROUP BY USING SQL
mysql> select Id,group_concat(Name SEPARATOR ',') as GroupConcatDemo from GroupConcatenateDemo group by Id;
+------+-----------------+
| Id | GroupConcatDemo |
+------+-----------------+
| 10 | Larry,Elon,Bob |
| 11 | Mike,Sam |
| 12 | John |
+------+-----------------+
Does Criteria Query / JPQL have equivalent of group_concat
or is there any other approach i can follow to achieve the above final output.
I have checked and tested both apis, they both seem to provide only concat
function which is not same as the SQL group_concat
.
Edit -
I Figured out how to register a db function -
I could use the GROUP_CONCAT
function from Criteria API. For this I had to add a Custom Dialect Class and inform spring(boot) about this class.
package com.mypackage;
import org.hibernate.dialect.MySQL8Dialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.StandardBasicTypes;
public class CustomMySQLDialect extends MySQL8Dialect {
public CustomMySQLDialect() {
super();
registerFunction(
"GROUP_CONCAT",
new StandardSQLFunction(
"GROUP_CONCAT",
StandardBasicTypes.STRING
)
);
}
}
And then inform spring boot about this class, in application.properties-
spring.jpa.properties.hibernate.dialect = com.mypackage.CustomMySQLDialect
Its working though but with issues -
- I am not able to figure out how to use the
SEPERATOR
, i want to use a separator other than the default,
(comma). - I also want to use
DISTINCT
,ORDER BY
features of group_concat.
How do i pass these through criteria api.
Current Situation -.
Currently my group_concat
code part of criteria query is something like below -
some other selects... , cb.function("GROUP_CONCAT", String.class, packagesJoin.get("packageName")), some other selects
and the generated sql part is - GROUP_CONCAT(packages4_.package_name) as col_3_0_,
.
And the output is - Package-1,Package-1,Package-2,Package-2
SOF Suggested situation -
like suggested by @jens-schauder (thanks jens) - if i use
cb.function( "group_concat", String.class, cb.concat( root.get("name"), cb.literal(",") )
i.e the code is
cb.function("GROUP_CONCAT", String.class, packagesJoin.get("packageName"), cb.literal(",")),
the generated sql is -
GROUP_CONCAT(packages4_.package_name,
',') as col_3_0_,
the output is:
Package-1,,Package-1,,Package-2,,Package-2,
Problem in this approach is - the ,
in cb.literal(",")
is concatenated with the column value. This should not happen and be resolved.
Wanted/Desired Situation -
The SQL I want to be generated is -
GROUP_CONCAT(DISTINCT packages4_.package_name ORDER BY packages4_.package_name DESC SEPARATOR ' # ') as col_3_0_,
.
And desired output is
Package-2 # Package-1
What more should i add to the criteria query. Any answers will be very much appreciated.... this is quite critical for me.