JOOQ:动态加入条件

Lui*_* C. 3 java jooq

我想从JOOQ 中的这个选择创建条件。因为在我的情况下,我想声明一个动态查询并仅在需要时检查 TABLE_C.FIELDC 是否包含“foo”...

示例

create.select().from(TABLE_A).join(TABLE_B).onKey(Keys.FK_TABLEA_TABLEB)
                    .join(TABLE_C).onKey(Keys.FK_TABLEB_TABLEC)
                    .where(TABLE_C.FIELDC.containsIgnoreCase("foo");
Run Code Online (Sandbox Code Playgroud)

到:

SelectFinalStep select = create.select().from(TABLEA);

if (isFooSearched) { 
   query.addCondition( <JOIN> and <CONTAINS> like first example) 
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

Luk*_*der 5

有几种方法可以解决这个问题:

使用隐式连接

在相对简单的情况下,当可选连接遵循一对一关系时,您可以使用隐式连接(如果您使用的是代码生成器):

create.select()
      .from(TABLE_A)
      .join(TABLE_B).onKey(Keys.FK_TABLEA_TABLEB)
      .where(isFooSearched
        ? TABLE_B.tableC().FIELDC.containsIgnoreCase("foo")
        : noCondition())
      .fetch();
Run Code Online (Sandbox Code Playgroud)

使用 SEMI JOIN 而不是 INNER JOIN,这使得动态 SQL 更容易

create.select()
      .from(TABLE_A)
      .where(
          isFooSearched
        ? TABLE_A.TABLE_B_ID.in(
              select(TABLE_B.ID)
             .from(TABLE_B)
             .join(TABLE_C).onKey(FK_TABLEB_TABLEC)
             .where(TABLE_C.FIELDC.containsIgnoreCase("foo"))
          )
        : trueCondition())
      .fetch();
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,半连接在形式上也比内部连接更正确,因为TABLE_A对于多对多关系中的任何匹配,您都不会得到任何重复的行(删除它们DISTINCT可能是错误的,而且肯定是低效的)。

旁注:与基于解决方案的解决方案相比,并非所有数据库都识别半连接EXISTSIN语法,因此可能无法以最佳方式运行此语句JOIN

按照您的要求使用 INNER JOIN

// I'm assuming DISTINCT is required here, as you
// - are not interested in TABLE_B and TABLE_C results (semi join semantics)
// - do not want any duplicate TABLE_A values
create.selectDistinct(TABLE_A.fields())
      .from(
          isFooSearched
        ? TABLE_A
             .join(TABLE_B).onKey(FK_TABLEA_TABLEB)
             .join(TABLE_C).onKey(FK_TABLEB_TABLEC)
          )
        : TABLE_A)
      .where(
          isFooSearched
        ? TABLE_C.FIELDC.containsIgnoreCase("foo")
        : trueCondition())
      .fetch();
Run Code Online (Sandbox Code Playgroud)

我在这里做了一些假设,包括这样一个事实,即DISTINCT在您加入的查询变体上的用法可能是正确的,但它(可能)在您的“默认”查询变体上伤害了您,所以也许,将它变成一个单一的动态查询可能有点矫枉过正。

因此...

使用两个不同的查询

根据我的口味,这两个查询足够简单,可以允许一些重复,只需根据标志运行两个不同的查询:

if (isFooSearched)
    create.select().from(TABLE_A) /* joins or semi joins here */ .fetch();
else
    create.select().from(TABLE_A).fetch();
Run Code Online (Sandbox Code Playgroud)

边注

所有解决方案都假设您的代码中有这些静态导入:

import static org.jooq.impl.DSL.*;
Run Code Online (Sandbox Code Playgroud)