【问题标题】:jOOQ join Select<?> objectjOOQ 加入 Select<?> 对象
【发布时间】:2018-11-23 20:51:58
【问题描述】:

我想在 SQL 中执行类似的操作:

SELECT 
  * 
FROM 
  tbl1 t1 
  INNER JOIN 
  (SELECT MAX(col1) as maxCol, col2 FROM tbl1 t1 GROUP BY t1.col2) subQ
  ON t1.col2 = subQ.col2
  AND t1.col1 = subQ.maxCol

在 jOOQ 中,我将 subQ 存储到 Select&lt;?&gt; 对象中:

Select<?> subQ = myDSL.select(DSL.max(TBL1.COL1).as("maxCol"), TBL1.COL2)
                      .from(TBL1)
                      .groupBy(TBL1.COL2);

我的问题是,如何从subQ 获取maxCol 列并在join 中使用它?我的join 是这样的:

select()
.from(TBL1)
.join(subQ.asTable())
.on(TBL1.COL1.eq(subQ.asTable().field("maxCol")));

.on() 有错误

字段类型中的方法eq(String)不适用于参数(Field)

我该怎么办?

【问题讨论】:

    标签: java mysql sql jooq


    【解决方案1】:

    使用 MySQL 8.0

    如果您使用的是 MySQL 8.0+,请不要使用子查询,而是使用窗口函数。这将是您的等效查询:

    SELECT *
    FROM (
      SELECT t1.*, RANK() OVER (PARTITION BY t1.col2 ORDER BY col1 DESC) rk
      FROM tbl1 t1
    ) t
    WHERE t.rk = 1
    

    优点是您只有一个tbl1 访问权限,这可能会运行得更快。

    This is often also called a TOP-n query. In other databases, there are other ways to implement this, see this article here.

    使用旧的 MySQL 版本

    如果您从任何表中通过未键入的名称(Stringorg.jooq.Name)访问字段,则编译器没有任何类型信息可用于生成的 Field&lt;?&gt;,这就是为什么您的原始代码没有t 编译。

    但是,您可以使用以下技术之一:

    记住原来的maxCol字段引用

    从您的子查询中,取出 maxCol 字段引用并将其分配给一个局部变量(假设它的类型为 Integer,如果需要,请替换):

    Field<Integer> maxCol = DSL.max(TBL1.COL1).as("maxCol");
    Select<?> subQ = myDSL.select(maxCol, TBL1.COL2).from(TBL1).groupBy(TBL1.COL2);
    

    现在,您还可以使用此引用从子查询中提取列:

    Field<Integer> subQMaxCol = subQ.field(maxCol);
    

    或直接在您的解决方案中内联:

    select().from(TBL1)
            .join(subQ.asTable())
            .on(TBL1.COL1.eq(subQ.field(maxCol)));
    

    TBL1.COL1 命名您的maxCol

    在这个特定的用例中,不引入任何新名称可能有意义,而是重新使用 COL1 作为名称:

    Select<?> subQ = myDSL.select(DSL.max(TBL1.COL1).as(TBL1.COL1), TBL1.COL2)
                          .from(TBL1)
                          .groupBy(TBL1.COL2);
    

    在这种情况下(如果没有不明确的 COL1 列名),您可以使用该引用再次从子查询中提取 COL1 字段:

    select().from(TBL1)
            .join(subQ.asTable())
            .on(TBL1.COL1.eq(subQ.field(TBL1.COL1)));
    

    使用TBL1.COL1 引用的数据类型

    从您的原始解决方案中,只需在从子查询中提取字段时添加数据类型:

    select().from(TBL1)
            .join(subQ.asTable())
            .on(TBL1.COL1.eq(subQ.field("maxCol", TBL1.COL1.getDataType())));
    

    或者,强制它:

    select().from(TBL1)
            .join(subQ.asTable())
            .on(TBL1.COL1.eq(subQ.field("maxCol").coerce(TBL1.COL1)));
    

    【讨论】:

      【解决方案2】:

      这样就解决了问题:

      select().from(TBL1).join(subQ.asTable()).on(TBL1.COL1.eq((Field<DataType>) subQ.field("maxCol")));
      

      【讨论】:

        猜你喜欢
        • 2016-06-17
        • 1970-01-01
        • 2015-02-12
        • 2021-03-30
        • 1970-01-01
        • 2021-02-06
        • 1970-01-01
        • 2019-08-09
        • 2013-10-02
        相关资源
        最近更新 更多