JOOQ派生表

问题描述 投票:1回答:1

我正在尝试在JOOQ中表达以下SQL。但是,我要么在使用派生表的类型方面遇到了很多问题,要么得到了可以编译的内容,但是在SQL级别甚至在JAVA中都失败了。谁能给我一个想法,在这种情况下如何正确使用派生表?

SELECT
    id,
    ROUND(num_realized / num_requirements, 2) AS realized_percent,
    ROUND(num_requirements / max_req, 2) AS activity_percent
FROM (
    SELECT
        requirement.project_id AS id,
        COUNT(requirement.id) AS num_requirements,
        COUNT(requirement.realized) AS num_realized
    FROM
        requirement
    GROUP BY
        requirement.project_id) AS stats
    CROSS JOIN (
        SELECT
            MAX(num_requirements) AS max_req
        FROM (
            SELECT
                requirement.project_id AS id,
                COUNT(requirement.id) AS num_requirements,
                COUNT(requirement.realized) AS num_realized
            FROM
                requirement
            GROUP BY
                requirement.project_id) AS stats) AS req_max 

该语句在SQL中应用时效果很好,但我无法将此表达式放入JOOQ。

我最近的尝试是使用

Table<Record3<Integer, Integer, Integer>> stats =
DSL.select(
    REQUIREMENT.PROJECT_ID.as("id"),
    DSL.count(REQUIREMENT.ID).as("num_requirements"),
    DSL.count(REQUIREMENT.REALIZED).as("num_realized")
).from(REQUIREMENT).groupBy(REQUIREMENT.PROJECT_ID).asTable("stats");

Table<Record2<Integer, Integer>> req_max =
    DSL.select(
        stats.field(0),
        DSL.min(stats.field(1))
    )
    .from(stats).asTable("req_max");

但是我遇到错误:不兼容的类型:

Table<Record2<CAP#1,CAP#2>> cannot be converted to Table<Record2<Integer,Integer>>

我尝试了很多不同的技术,包括定义数据类型和使用.field(String,Datatype)而不是使用“ Records”,但是无论我做什么,它要么无法编译,要么在执行未知错误时失败。

我很乐意提供帮助。

java sql jooq
1个回答
0
投票

改为使用窗口功能

通常,应尽可能避免自我联接。在许多情况下,与嵌套查询中的聚合相比,窗口函数可以解决问题得多。如果您使用的是MySQL 8,则查询可以重写为:

SELECT
    requirement.project_id AS id,
    ROUND(COUNT(requirement.realized) / COUNT(requirement.id), 2) AS realized_percent,
    ROUND(COUNT(requirement.id) / MAX(COUNT(requirement.id)) OVER(), 2) AS activity_percent
FROM
    requirement
GROUP BY
    requirement.project_id    

注意MAX(..) OVER() window function, which can aggregate ordinary aggregation functions as explained here。我知道您使用的是MySQL 5.7,但尚不支持窗口功能,但出于完整性考虑,此答案需要基于窗口功能的解决方案-可能是出于升级动机:-)

首先可以通过简化基础SQL查询来简化许多复杂的jOOQ查询。

您遇到的派生表问题

问题是您使用stats.field(0)stats.field(0)。方法签名是

stats.field(1)

当按索引访问表的列时,jOOQ不可能为您提供类型安全,因此返回类型为Field<?> field​(int index) ,其中列类型为通用通配符。这里有一些解决方案:

  1. 如果不需要,请避免类型安全。您始终可以声明表Field<?>。仅从您的示例来看,我不确定此处是否需要任何类型安全性
  2. 将字段引用提取为局部变量。而不是例如嵌入Table<?> req_max表中的id列,为什么不这样做:

    stats

    然后像这样使用它:

    Field<Integer> id = REQUIREMENT.PROJECT_ID.as("id");
    Field<Integer> numRequirements = DSL.count(REQUIREMENT.ID).as("num_requirements");
    Field<Integer> numRealized = DSL.count(REQUIREMENT.REALIZED).as("num_realized");
    
© www.soinside.com 2019 - 2024. All rights reserved.