JPA2.2 + SELECT 中的子查询用于聚合

JPA2.2 + Subquery in SELECT for aggregation

我正在这里开发 Spring Boot 2.3。1.RELEASE 应用程序,它带来了 Hibernate 5.4 + JPA 2.2。

数据库(此处缩写): Table 1 (sri):

id | fund_id
 1 | 20
 2 | 21
 3 | 22

Table 2(参考):

  id | SECURITY_ID | FUND_PROPORTION | value
 100 |           1 |             0.2 |    70
 101 |           1 |             0.1 |    20
 102 |           1 |             0.5 |    60
 103 |           2 |             0.1 |    95
 104 |           2 |             0.1 |    23
 105 |           2 |             0.2 |    48
 106 |           3 |             0.4 |    65
 107 |           3 |             0.5 |    16
 108 |           3 |             0.2 |    32

...实际值不相关 - 只是为了展示我如何获得这些值。

我需要select数据库中的值,但由于结果量很大,我希望数据库进行计算。这就是为什么我设置了以下查询(此处 post 的缩写)查询,它在数据库上使用纯 SQL 完美运行:

select 
    RATING, 
    SUM(FUND_PROPORTION),
    COUNT(FUND_PROPORTION)
from (
SELECT 
    ref.FUND_PROPORTION as FUND_PROPORTION ,  
    Case 
        when ref.value <= 100 AND ref.value > 90 then 'A' 
        when ref.value <= 90  AND ref.value > 75 then 'B' 
        when ref.value <= 75  AND ref.value > 50 then 'C' 
        when ref.value <= 50  AND ref.value > 25 then 'D' 
        when ref.value <= 25  AND ref.value > 10 then 'E' 
        when ref.value <= 10  then 'F' 
    END  AS RATING
FROM 
    table1 sri,
    table2 ref 
WHERE 
    sri.id = ref.SECURITY_ID 
    AND sri.fund_id = SOME ID
    GROUP BY FUND_PROPORTION, RATING
) as t1
group by RATING;

这 return 是预期的结果:

RATING    SUM(FUND_PROPORTION)    COUNT(FUND_PROPORTION)
B         0.32                    1
C         0.28                    2
D         0.14                    5
E         0.03                    7
F         0.01                    8

...基本上我需要有一组所有 FUND_PROPORTIONS 和评级,它通过根据它的值(由案例语句定义)给它一个名称来标识该集合。然后 运行 在该值上 count/sum 和 return 它。

我的问题:我在 Java 中 运行 无法得到它。启动存储库(JpaRepository 或 JpaCustomRepository)后,它会抱怨“额外的”“(”——这是子查询的开始。 似乎我不能在(主)查询的 SELECT 部分有子查询。

我试过使用本机查询,但由于我们使用的是 UUID,驱动程序尝试转换值 ti byte[] 但失败了(惊奇,惊奇)。我试过使用 CriteriaAPI,但我能找到的所有示例都是关于在 WHERE 部分中使用子查询的 - 这对我没有帮助。

当然,我可以 运行 运行 只是子查询并直接在 Java 中组合这些值,但这意味着将大量数据加载到应用程序中 - 这是这不是我想要发生的(结果来自一个小型测试数据库,产品在数量上看起来会有所不同)。

现在,我绝对愿意将上面的查询转换为其他内容,例如加入。但我不知道如何重写查询。

有什么想法吗? JPA(最喜欢的)、Criteria Api 或完全重写 - 构成这件事的所有内容+运行ning 都可以。

非常感谢。

PS:周末我会在山上,所以在 7 月 20 日星期一之前我身边没有 read/response。

在注释中使用 nativeQuery 属性以使用 SQL

@Query(
  value = "SELECT ...", 
  nativeQuery = true
)

Lukas Eder/User - Upvote don't say Thanks感谢您的支持。使用 nativeQuery 属性并不是完整的答案,但最终让我找到了以下解决方案:

在这里使用 nativeQuery = true 不起作用,因为您基本上失去了 Hibernate 对定义响应对象的支持(抱歉,这不是我最初请求的一部分)。

所以现在我切换到 CustomRepository,添加 META-INF/orm.xml,定义响应对象:

<entity-mappings version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd">
<sql-result-set-mapping name="DistributionSearchResult">
    <constructor-result target-class="searchresult.DistributionSearchResult">
        <column name="RATING" class="java.lang.String"/>
        <column name="sum" class="java.math.BigDecimal"/>
        <column name="count" class="java.lang.Long"/>
    </constructor-result>
</sql-result-set-mapping>

创建nativeQuery时引用了如下定义:

final String queryString = " SELECT " +
                "   RATING, " +
                "   SUM(FUND_PROPORTION) as sum, " +
                "   COUNT(FUND_PROPORTION) as count" +
                " FROM ( " +
                "   SELECT " +
                "       ref.fund_Proportion as FUND_PROPORTION, " +
                "       CASE " +
                "          when ref.value <= 100 AND ref.value > 90 then 'A' " +
                "          when ref.value <= 90  AND ref.value > 75 then 'B' " +
                "          when ref.value <= 75  AND ref.value > 50 then 'C' " +
                "          when ref.value <= 50  AND ref.value > 25 then 'D' " +
                "          when ref.value <= 25  AND ref.value > 10 then 'E' " +
                "          when ref.value <= 10  then 'F' " +
                "       END AS RATING " +
                "   FROM " +
                "       Security_Provider_Info spi, " +
                "       SCORE_ESG_REFINITIV_SEC_PROV ref " +
                "   WHERE " +
                "       sri.id = ref.SECURITY_ID " +
                "       AND sri.fund_id = :SOME_ID " +
                "   ) as t1 " +
                "   GROUP BY RATING ";

    /* set Parameter */
    final JpaQueryParameters parameters = new JpaQueryParameters();
    parameters.setParameter("SOME_ID", 123);

    /* see orm.xml for definition of DistributionSearchResult */
    final Query query = entityManager.createNativeQuery(queryString, "DistributionSearchResult");
    parameters.addParameters(query);

这样,结果按要求分组并被推送到我的 DistributionSearchResult 类型的结果对象中。

非常感谢:)