H2 用户定义的聚合函数 ListAgg 不能在第一个参数上使用 DISTINCT 或 TRIM()
Posted
技术标签:
【中文标题】H2 用户定义的聚合函数 ListAgg 不能在第一个参数上使用 DISTINCT 或 TRIM()【英文标题】:H2 User defined aggregate function, ListAgg, can't use DISTINCT or TRIM() on the first parameter 【发布时间】:2015-10-09 21:01:52 【问题描述】:所以我有一个 DB2 生产数据库,我需要在其中使用可用的函数 ListAgg。我希望我的单元测试使用 H2 来正确测试这个功能。不幸的是,H2 不直接支持 ListAgg。但是,我可以创建一个用户定义的聚合函数...
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.h2.api.AggregateFunction;
import com.google.common.base.Joiner;
public class ListAgg implements AggregateFunction
private List<String> values = new ArrayList<String>();
private String delimiter = ",";
@Override
public void init(Connection conn) throws SQLException
@Override
public int getType(int[] inputTypes) throws SQLException
if (inputTypes.length != 2)
throw new java.sql.SQLException("The aggregate function ListAgg must have 2 arguments.");
return java.sql.Types.VARCHAR;
@Override
public void add(Object sqlValues) throws SQLException
Object[] objects = (Object[]) sqlValues;
this.delimiter = (String) objects[1];
String value = (String) objects[0];
values.add(value);
@Override
public Object getResult() throws SQLException
return Joiner.on(delimiter).join(values);
我已经做到了。这适用于
ListAgg(columnName, ',')
但失败了
ListAgg(DISTINCT TRIM(columnName), ',')
我错过了什么?
编辑: 我收到以下错误消息:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback;
bad SQL grammar [select ..., LISTAGG(DISTINCT TRIM(columnName), ',') as
columnName_LIST, from ... group by ...]; nested exception is
org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "SELECT ... ";
expected "NOT, EXISTS, INTERSECTS, SELECT, FROM"; SQL statement:
select ... from ... group by ... [42001-174]
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:231)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
EDIT2:
COUNT()
是否也实现了 AggregateFunction 还是在内部使用了其他东西?因为H2能够处理COUNT(DISTINCT columnName)
【问题讨论】:
从版本 1.4.198 (2019-02-22) 开始,H2 实现了 LISTAGG - 请参阅 changelog。它被描述为“部分”,但文档中的示例至少包括LISTAGG(NAME, ', ') WITHIN GROUP (ORDER BY ID)
和 LISTAGG(ID, ', ') WITHIN GROUP (ORDER BY ID) OVER (ORDER BY ID)
【参考方案1】:
我认为 H2 不允许您在自定义聚合函数上使用 DISTINCT
关键字。但是您可以轻松定义自己的“独特”版本的ListAgg
:
public class DistinctListAgg implements AggregateFunction
private Set<String> values = new LinkedHashSet<String>();
// The rest is the same
【讨论】:
感谢您的宝贵时间。我很欣赏有关如何获得独特版本的见解。但我希望能够在不更改环境之间的代码的情况下进行测试。在这种情况下,我将在生产中运行 ListAgg(DISTINCT TRIM(columnName)),在单元测试中运行 [Distinct]ListAgg(columnName)。 嗯,DB2'sLISTAGG
真的支持DISTINCT
吗?这是一个未记录的功能吗?无论如何,我怀疑当您不直接在 DB2 上进行集成测试时,您会一次又一次地遇到这些差异
LISTAGG
支持DISTINCT
真的那么令人惊讶吗? COUNT
和 SUM
也是支持它的 (DB2) 聚合函数。
嗯,它没有记录,不幸的是,Oracle 的LISTAGG
不支持它。以上是关于H2 用户定义的聚合函数 ListAgg 不能在第一个参数上使用 DISTINCT 或 TRIM()的主要内容,如果未能解决你的问题,请参考以下文章
oracle 聚合函数 LISTAGG ,将多行结果合并成一行
MySQL 中的聚合函数 - 列表(如 Oracle 中的 LISTAGG)