使用 Spring JPA 为 STRING_AGG 设置聚合函数,并使用 Postgresql 作为 Group_By

ALM*_*ALM 5 java spring jpa aggregate-functions spring-data-jpa

我正在尝试设置一个repository调用来ids检索GROUP_BY. 我可以使用它来工作createNativeQuery,但我无法使用 Spring 来使它工作JPA工作FUNCTION

\n\n
FUNCTION(\'string_agg\', FUNCTION(\'to_char\',r.id, \'999999999999\'), \',\')) as ids\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

问题

\n\n
    \n
  1. 如果有人可以帮助我设置正确的函数调用\n如下面的 JPA 示例所示,我将不胜感激。
  2. \n
\n\n

更新1

\n\n

实现自定义方言后,看起来它试图将函数转换为long. 功能代码是否正确?

\n\n
FUNCTION(\'string_agg\', FUNCTION(\'to_char\',r.id, \'999999999999\'), \',\'))\n
Run Code Online (Sandbox Code Playgroud)\n\n

更新2

\n\n

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

\n\n

这是我的代码:

\n\n

数据传输组织

\n\n
    @Data\n    @NoArgsConstructor\n    @AllArgsConstructor\n    public class TestScriptErrorAnalysisDto {\n        private String testScriptName;\n        private String testScriptVersion;\n        private String checkpointName;\n        private String actionName;\n        private String errorMessage;\n        private Long count;\n        private String testResultIds;\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

控制器

\n\n
@RequestMapping(method = RequestMethod.GET)\n@ResponseBody\npublic ResponseEntity<Set<TestScriptErrorAnalysisDto>> getTestScriptErrorsByExecutionId(@RequestParam("executionId") Long executionId) throws Exception {\n\n    return new ResponseEntity<Set<TestScriptErrorAnalysisDto>>(testScriptErrorAnalysisRepository.findTestScriptErrorsByExecutionId(executionId), HttpStatus.OK);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

存储库尝试使用函数不起作用

\n\n
    @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\'), \',\')) "\n    + "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 "\n    + "GROUP by r.testScriptName, r.testScriptVersion, c.name, ac.name, ac.errorMessage " + "ORDER by ec desc")\nSet<TestScriptErrorAnalysisDto> findTestScriptErrorsByExecutionId(@Param("executionId") Long executionId);\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用 createNativeQuery工作的存储库

\n\n
    List<Object[]> errorObjects = entityManager.createNativeQuery(\n            "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 "\n                    + "FROM action ac, checkpoint c, test_result r " + "WHERE ac.status = \'Failed\' " + "AND ac.checkpoint_id = c.id "\n                    + "AND r.id = c.test_result_id " + "AND r.test_run_execution_log_id = ? "\n                    + "GROUP by r.test_script_name, r.test_script_version, c.name, ac.name, ac.error_message " + "ORDER by ec desc")\n    .setParameter(1, test_run_execution_log_id).getResultList();\n\n    for (Object[] obj : errorObjects) {\n        for (Object ind : obj) {\n            log.debug("Value: " + ind.toString());\n            log.debug("Value: " + ind.getClass());\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我在 FUNCTION 上找到的文档

\n\n
            4.6.17.3 Invocation of Predefined and User-defined Database Functions\n\n    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.\n\n     function_invocation::= FUNCTION(function_name {, function_arg}*)\n     function_arg ::=\n             literal |\n             state_valued_path_expression |\n             input_parameter |\n             scalar_expression\n    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.\n\n    The function may be a database-defined function or a user-defined function. The function may be a scalar function or an aggregate function.\n\n    Applications that use the function_invocation syntax will not be portable across databases.\n\n    Example:\n\n    SELECT c\n    FROM Customer c\n    WHERE FUNCTION(\xe2\x80\x98hasGoodCredit\xe2\x80\x99, c.balance, c.creditLimit)\n
Run Code Online (Sandbox Code Playgroud)\n

ALM*_*ALM 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"));
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

更新后就new org.hibernate.type.StringType()可以了。

            registerFunction("string_agg", new StandardSQLFunction("string_agg", new org.hibernate.type.StringType()));
Run Code Online (Sandbox Code Playgroud)