首页 > 解决方案 > jooq 嵌套选择和类型安全

问题描述

我正在尝试在jooq中编写以下sql:

SELECT SUM(`sum`) AS `total`
FROM(
        SELECT
        MIN(`num_views`) AS `sum`
        FROM `fact_wishlist`
        GROUP BY `id`
) AS t

我发现了一些适用于此的东西:

Table<Record2<String, Integer>> nested = 
    table(create.select(MYTABLE.ID,
    min(MYTABLE.NUM_VIEWS)
            .as("views"))
    .from(MYTABLE)
    .groupBy(MYTABLE.ID));

return create.select(sum((Field<Integer>) nested.field("views")))
    .from(nested)
    .fetchOne().value1().longValue();

但是,不知何故,我失去了类型安全性。我觉得我在做一些明显的错误,但我没有看到它。关于如何改进的任何想法?

标签: javasqljooq

解决方案


不幸的是,您无法在 jOOQ 中使用派生表实现 100% 的类型安全,因为 Java 编译器无法真正证明派生表包含列。但是您的使用肯定可以通过重用该"views"字段来改善。只需将其分配给局部变量即可。

Field<Integer> views = min(MYTABLE.NUM_VIEWS).as("views");

Table<Record2<String, Integer>> nested = 
    table(create.select(MYTABLE.ID, min(views))
    .from(MYTABLE)
    .groupBy(MYTABLE.ID));

return create.select(sum(nested.field(views)))
    .from(nested)
    .fetchOne().value1().longValue();

请注意该Table.field(Field<T>)方法如何允许维护<T>类型引用,假设您传入的字段确实存在于派生表中,按其给定名称,并且它与您的参数字段的类型匹配。

使用窗口函数的替代方法

请注意,您的查询可以使用窗口函数重写,如下所示。

SELECT SUM(MIN(num_views)) OVER ()
FROM fact_wishlist
GROUP BY id
LIMIT 1

或者在 jOOQ 中:

return
create.select(sum(min(MYTABLE.NUM_VIEWS)).over())
      .from(MYTABLE)
      .groupBy(MYTABLE.ID)
      .limit(inline(1))
      .fetchSingle()
      .value1().longValue();

这当然取决于您的数据库是否支持窗口函数,并且它可能比您的双重聚合解决方案更快/更慢,这也取决于供应商。


推荐阅读