【问题标题】:Using Spring JPA to setup a Aggregate Function for STRING_AGG with Postgresql for a Group_By使用 Spring JPA 为 STRING_AGG 设置聚合函数,使用 Postgresql 为 Group_By
【发布时间】:2017-12-19 01:27:29
【问题描述】:

我正在尝试设置一个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。请参阅下面的解决方案。

这是我的代码:

DTO

    @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;
    }

控制器

@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 working

的存储库
    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)

【问题讨论】:

  • 这是一个错字FUNCTION('string_agFUCNTIONTION('to_char',r.id, '999999999999'), ',')) ??
  • @JorgeCampos 是的,我已经更新了它,但它似乎仍然无法正常工作。
  • “不起作用”。想知道这意味着什么
  • @DN1 "不起作用",上面描述了它试图把 FUNCTION('string_agg', FUNCTION('to_char',r.id, '999999999999'), ' ,')) 变成长而不是字符串。
  • 所以在你选择的 JPA 提供者上提出一个 BUG。你的 JPQL 是完全有效的,它是由 JPA 提供者处理映射到构造函数表达式

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


【解决方案1】:

最后缺少的主要部分是通过创建一个新类来扩展 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()));

【讨论】:

  • 如何为 microsoft sql (mssql) 注册 'string_agg' 函数?
猜你喜欢
  • 2013-12-24
  • 1970-01-01
  • 2013-02-05
  • 1970-01-01
  • 1970-01-01
  • 2018-06-02
  • 2018-07-10
  • 2015-07-20
  • 1970-01-01
相关资源
最近更新 更多