有几种方法可以解决这个问题:
使用隐式连接
在相对简单的情况下,当可选连接遵循一对一关系时,您可以使用implicit join(如果您使用代码生成器):
create.select()
.from(TABLE_A)
.join(TABLE_B).onKey(Keys.FK_TABLEA_TABLEB)
.where(isFooSearched
? TABLE_B.tableC().FIELDC.containsIgnoreCase("foo")
: noCondition())
.fetch();
使用 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();
请注意,在这种情况下,半连接也比内连接更正式正确,因为对于多对关系中的任何匹配项,您不会在 TABLE_A 上获得任何重复行(使用 DISTINCT 删除它们可能是错误,而且肯定是低效的)。
旁注:与基于 JOIN 的解决方案相比,并非所有数据库都能识别 EXISTS 或 IN 语法中的半连接,因此可能无法以最佳方式运行此语句。
按照您的要求使用 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();
我在这里做了一些假设,包括DISTINCT 的使用在您的查询的连接变体上可能是正确的,但它(可能)在您的“默认”查询变体上伤害了您,所以也许,将其放入单个动态查询中可能是矫枉过正。
这样……
使用两个不同的查询
根据我的口味,这两个查询非常简单,可以允许一些重复,并且只需根据标志运行两个不同的查询:
if (isFooSearched)
create.select().from(TABLE_A) /* joins or semi joins here */ .fetch();
else
create.select().from(TABLE_A).fetch();
旁注
所有解决方案都假设您的代码中有这些静态导入:
import static org.jooq.impl.DSL.*;