I have following Hibernate forumla query, which I am able to execute in mysql workbanch.
select group_concat(distinct t.column_1_name SEPARATOR ', ') from table_name t and t.fk_record_id = record_id
While executing this query with Hibernate, hibernate is appending parent table to the SEPRATOR key word as shown in the below query.
select group_concat(distinct t.column_1_name parent_table.SEPARATOR ', ') from table_name t and t.fk_record_id = record_id
Here hibernate is not treating SEPRATOR as keyword. Anyone has any idea about this?
You can add SEPARATOR
as keyword. Implement your own DialectResolver
and add the keyword in lower case to the resulting dialect:
public class MyDialectResolver implements DialectResolver {
public Dialect resolveDialect(DialectResolutionInfo info) {
for (Database database : Database.values()) {
Dialect dialect = database.resolveDialect(info);
if (dialect != null) {
dialect.getKeywords().add("separator");
return dialect;
}
}
return null;
}
}
The same for Hibernate versions before 5.2.13 / 5.3.0:
public class MyDialectResolver extends StandardDialectResolver {
protected Dialect resolveDialectInternal(DatabaseMetaData metaData) throws SQLException {
Dialect dialect = super.resolveDialectInternal(metaData);
dialect.getKeywords().add("separator");
return dialect;
}
}
You will then have to tell Hibernate to use your dialect resolver. For example in JPA you can do this in your persistence.xml:
<persistence>
<persistence-unit>
...
<property name="hibernate.dialect_resolvers" value="mypackage.MyDialectResolver"/>
</persistence-unit>
</persistence>
The same applies to aggregating functions in other dialects. For example in Oracle the WITHIN
keyword is missing.
There is another option, which is more database independent (and which I prefer). Create the following SQLFunction
:
public class ListAggFunction implements SQLFunction {
/**
* The pattern that describes how the function is build in SQL.
*
* Replacements:
* {path} - is replaced with the path of the list attribute
* {separator} - is replaced with the separator (defaults to '')
* {orderByPath} - is replaced by the path that is used for ordering the elements of the list
*/
private String pattern;
/**
* Creates a new ListAggFunction definition which uses the ANSI SQL:2016 syntax.
*/
public ListAggFunction() {
this("LISTAGG(DISTINCT {path}, {separator}) WITHIN GROUP(ORDER BY {orderByPath})");
}
/**
* Creates a new ListAggFunction definition which uses a database specific syntax.
*
* @param pattern The pattern that describes how the function is build in SQL.
*/
public ListAggFunction(String pattern) {
this.pattern = pattern;
}
public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException {
return StringType.INSTANCE;
}
public boolean hasArguments() {
return true;
}
public boolean hasParenthesesIfNoArguments() {
return true;
}
public String render(Type firstArgumentType, List arguments,
SessionFactoryImplementor factory) throws QueryException {
if (arguments.isEmpty() || arguments.size() > 3) {
throw new IllegalArgumentException(
"Expected arguments for 'listagg': path [, separator [, order by path]]");
}
String path = (String) arguments.get(0);
String separator = arguments.size() < 2 ? "''" : (String) arguments.get(1);
String orderByPath = arguments.size() <= 2 ? path : (String) arguments.get(2);
return StringUtils.replaceEach(this.pattern, new String[] { "{path}", "{separator}", "{orderByPath}" },
new String[] { path, separator, orderByPath });
}
}
You can register this function in the DialectResolver the same way as the keyword above:
if ("MySQL".equals(info.getDatabaseName()) || "H2".equals(info.getDatabaseName())) {
dialect.getFunctions().put("listagg", new ListAggFunction("GROUP_CONCAT(DISTINCT {path} ORDER BY {orderByPath} SEPARATOR {separator})"));
} else {
dialect.getFunctions().put("listagg", new ListAggFunction());
}
Now you can use this function in your JPQL / HQL / Criteria queries without thinking about the syntax of the dialect:
SELECT e.group, listagg(e.stringProperty, ', ') FROM Entity e GROUP BY e.group
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With