简体   繁体   English

JOOQ:动态加入条件

[英]JOOQ: Dynamic join conditions

I would like to create conditions from this select in JOOQ.我想从 JOOQ 中的这个选择创建条件 Because in my case I want to declare a dynamic query and check if TABLE_C.FIELDC contains "foo" only when I need...因为在我的情况下,我想声明一个动态查询并仅在需要时检查 TABLE_C.FIELDC 是否包含“foo”...

Example :示例

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");

to:到:

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

if (isFooSearched) { 
   query.addCondition( <JOIN> and <CONTAINS> like first example) 
}

How can I do this?我该怎么做?

There are several ways to solve this:有几种方法可以解决这个问题:

Using implicit joins使用隐式连接

In relatively simple cases, when the optional join follows a to-one relationship, you may be able to use an implicit join (if you're using the code generator):在相对简单的情况下,当可选连接遵循一对一关系时,您可以使用隐式连接(如果您使用的是代码生成器):

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

Using SEMI JOIN instead of INNER JOIN, which makes dynamic SQL much easier使用 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();

Note that a semi join is also more formally correct in this case than an inner join, as you will not get any duplicate rows on TABLE_A for any matches in to-many relationships (removing them with DISTINCT might be wrong and certainly is inefficient).请注意,在这种情况下,半连接在形式上也比内部连接更正确,因为对于多对多关系中的任何匹配,您不会在TABLE_A上获得任何重复行(用DISTINCT删除它们可能是错误的,而且肯定是低效的)。

Side-note: Not all databases recognise semi-joins in EXISTS or IN syntax, and may thus not optimally run this statement, compared to a JOIN based solution.旁注:与基于JOIN的解决方案相比,并非所有数据库都识别EXISTSIN语法中的半连接,因此可能无法以最佳方式运行此语句。

Using INNER JOIN as you asked for按照您的要求使用 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();

I've mad a few assumptions here, including the fact that DISTINCT usage could be correct on your joined variant of the query, but it is hurting you (probably) on your "default" query variant, so perhaps, shoe horning this into a single dynamic query might be overkill.我在这里做了一些假设,包括DISTINCT用法在您的查询的联接变体上可能是正确的这一事实,但它在您的“默认”查询变体上(可能)伤害了您,所以也许,把它变成一个单个动态查询可能有点矫枉过正。

Thus...因此...

Using two different queries使用两个不同的查询

For my taste, the two queries are simple enough to allow for some duplication and simply run two different queries depending on the flag:根据我的口味,这两个查询足够简单,可以允许一些重复,只需根据标志运行两个不同的查询:

if (isFooSearched)
    create.select().from(TABLE_A) /* joins or semi joins here */ .fetch();
else
    create.select().from(TABLE_A).fetch();

Side note旁注

All solutions are assuming you have these static imports in your code:所有解决方案都假设您的代码中有这些静态导入:

import static org.jooq.impl.DSL.*;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM