java - 使用 Spring JPA 为 STRING_AGG 和 Postgresql 为 Group_By 设置聚合函数

标签 java spring jpa spring-data-jpa aggregate-functions

我正在尝试设置一个 repository 调用来检索 GROUP_BY 中使用的测试结果 ids 列表的 ID。我可以使用 createNativeQuery 让它工作,但我无法使用 Spring 的 JPAFUNCTION 调用让它工作。

FUNCTION('string_agg', FUNCTION('to_char',r.id, '999999999999'), ',')) as ids

我正在使用 Spring Boot 1.4、hibernate 和 PostgreSQL。

问题

  1. 如果有人可以帮我设置正确的函数调用 在下面的 JPA 示例中显示,我们将不胜感激。

更新 1

在实现自定义方言后,它看起来像是在尝试将函数转换为 long。函数代码是否正确?

FUNCTION('string_agg', FUNCTION('to_char',r.id, '999999999999'), ','))

更新 2

进一步研究方言后,您似乎需要为函数注册返回类型,否则它将默认为 long。请参阅下面的解决方案。

这是我的代码:

数据传输

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class TestScriptErrorAnalysisDto {
        private String testScriptName;
        private String testScriptVersion;
        private String checkpointName;
        private String actionName;
        private String errorMessage;
        private Long count;
        private String testResultIds;
    }

Controller

@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<Set<TestScriptErrorAnalysisDto>> getTestScriptErrorsByExecutionId(@RequestParam("executionId") Long executionId) throws Exception {

    return new ResponseEntity<Set<TestScriptErrorAnalysisDto>>(testScriptErrorAnalysisRepository.findTestScriptErrorsByExecutionId(executionId), HttpStatus.OK);
}

尝试使用函数的存储库不工作

    @Query(value = "SELECT new com.dto.TestScriptErrorAnalysisDto(r.testScriptName, r.testScriptVersion, c.name, ac.name, ac.errorMessage, count(*) as ec, FUNCTION('string_agg', FUNCTION('to_char',r.id, '999999999999'), ',')) "
    + "FROM Action ac, Checkpoint c, TestResult r " + "WHERE ac.status = 'Failed' " + "AND ac.checkpoint = c.id " + "AND r.id = c.testResult " + "AND r.testRunExecutionLogId = :executionId "
    + "GROUP by r.testScriptName, r.testScriptVersion, c.name, ac.name, ac.errorMessage " + "ORDER by ec desc")
Set<TestScriptErrorAnalysisDto> findTestScriptErrorsByExecutionId(@Param("executionId") Long executionId);

使用 createNativeQuery 的存储库有效

    List<Object[]> errorObjects = entityManager.createNativeQuery(
            "SELECT r.test_script_name, r.test_script_version, c.name as checkpoint_name, ac.name as action_name, ac.error_message, count(*) as ec, string_agg(to_char(r.id, '999999999999'), ',') as test_result_ids "
                    + "FROM action ac, checkpoint c, test_result r " + "WHERE ac.status = 'Failed' " + "AND ac.checkpoint_id = c.id "
                    + "AND r.id = c.test_result_id " + "AND r.test_run_execution_log_id = ? "
                    + "GROUP by r.test_script_name, r.test_script_version, c.name, ac.name, ac.error_message " + "ORDER by ec desc")
    .setParameter(1, test_run_execution_log_id).getResultList();

    for (Object[] obj : errorObjects) {
        for (Object ind : obj) {
            log.debug("Value: " + ind.toString());
            log.debug("Value: " + ind.getClass());
        }
    }

这是我在 FUNCTION 上找到的文档

            4.6.17.3 Invocation of Predefined and User-defined Database Functions

    The invocation of functions other than the built-in functions of the Java Persistence query language is supported by means of the function_invocation syntax. This includes the invocation of predefined database functions and user-defined database functions.

     function_invocation::= FUNCTION(function_name {, function_arg}*)
     function_arg ::=
             literal |
             state_valued_path_expression |
             input_parameter |
             scalar_expression
    The function_name argument is a string that denotes the database function that is to be invoked. The arguments must be suitable for the database function that is to be invoked. The result of the function must be suitable for the invocation context.

    The function may be a database-defined function or a user-defined function. The function may be a scalar function or an aggregate function.

    Applications that use the function_invocation syntax will not be portable across databases.

    Example:

    SELECT c
    FROM Customer c
    WHERE FUNCTION(‘hasGoodCredit’, c.balance, c.creditLimit)

最佳答案

最后缺少的主要部分是通过创建一个新类来扩展 PostgreSQL94Dialect 来定义函数。由于这些函数不是为方言定义的,因此它们不会在调用中处理。

    public class MCBPostgreSQL9Dialect extends PostgreSQL94Dialect {

        public MCBPostgreSQL9Dialect() {
            super();
            registerFunction("string_agg", new StandardSQLFunction("string_agg", new org.hibernate.type.StringType()));
            registerFunction("to_char", new StandardSQLFunction("to_char"));
            registerFunction("trim", new StandardSQLFunction("trim"));
        }
    }

另一个问题是需要在注册时为函数的返回类型设置一个类型。我得到了一个 long 返回,因为默认情况下 registerFunction 返回一个 long,即使 string_agg 会在 postgres 的 sql 查询中返回一个字符串。

在用 new org.hibernate.type.StringType() 更新后它起作用了。

            registerFunction("string_agg", new StandardSQLFunction("string_agg", new org.hibernate.type.StringType()));

关于java - 使用 Spring JPA 为 STRING_AGG 和 Postgresql 为 Group_By 设置聚合函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47878811/

相关文章:

java - 两个@RequestMapping注解的区别

Java时间在Mysql表中插入

java - 在 JPA 中从集合中的枚举搜索时类型错误

java - 导出到 json 时生成的数据库实体的循环依赖

java - MainFragment 处的 NullPointerException

java - Action类通过ajax调用从jsp页面获取null值

spring - 为什么spring客户端无法获取spring配置服务器属性?

java - 如何通过单击按钮打开新 Activity ?

java - 如何在 JavaFX 中展开和折叠 TitledPane

spring - 配置服务器配置无效