目前我在我的项目中使用最新的jOOQ 3.19.5(R2dbc/Postgres)。
我也遇到过这样的问题。
给出
master
和详细信息表。
|master |
id,
type
|details|
id,
master_id,
other_id // connect other tables.
我想从外部参数中查询主表和详细信息以及以下条件:
我尝试使用以下查询子句:
dslContext
.select(
master.id,
...other master fields,
multiple(
select(details.id, details.other_id)
.from(details)
.where(details.master_id.eq(masters.id).and(details.other_id.eq(other_id_param))
)
)
.from(master)
.where(master.type.eq(type_param))
但是此查询将包括所有类型为
type_param
的大师,并带有一些空的详细信息。
我尝试添加一个
count
子选择子句作为字段来过滤掉这样的结果。
dslContext
.select(
master.id,
...other master fields,
multiple(
select(details.id, details.other_id)
.from(details)
.where(details.master_id.eq(masters.id).and(details.other_id.eq(other_id_param))
),
select(field("count(*)", BIGINT))
.from(details)
.where(details.master_id.eq(masters.id).and(details.other_id.eq(other_id_param))
.asField<Long>("details_count")
)
.from(master)
.where(master.type.eq(type_param).and(field("details_count").greaterThat(0)))
不行,生成的SQL报错:
column "details_count" does not exist
当我在其中添加
exists
时,它就起作用了。
dslContext
.select(
master.id,
...other master fields,
multiple(
select(details.id, details.other_id)
.from(details)
.where(details.master_id.eq(masters.id)
.and(details.other_id.eq(other_id_param))
)
)
.from(master)
.where(master.type.eq(type_param)
.andExists(
selectOne()
.from(details)
.where(details.master_id.eq(masters.id)
.and(details.other_id.eq(other_id_param))
)
是否有更好的 SQL 来在一次查询中选择
master/details
并按 detail
的属性进行过滤?
由于 SQL 中操作的
逻辑顺序,您无法使用在
WHERE
子句中投影的 SELECT
来过滤任何内容。
为了使您的
COUNT(*)
值可用于您的 WHERE
子句,您必须将其推入 FROM
子句中,例如通过使用派生表,或使用LATERAL
-
在你的具体情况下它会起作用。我也在这里描述了这种技术,其中 LATERAL
用于在 SQL 中创建“本地列变量”
例如这可行:
// Create a derived table
val t =
select(count())
.from(details)
.where(details.master_id.eq(master.id))
.and(details.other_id.eq(other_id_param))
.asTable("t", "c")
// Dereference the count column from it
val c = t.field("c", INTEGER);
dslContext
.select(
master.id,
// ...other master fields,
multiset(
select(details.id, details.other_id)
.from(details)
.where(details.master_id.eq(master.id))
.and(details.other_id.eq(other_id_param))),
// Project the count
c
)
.from(master)
// Lateral join it
.crossJoin(lateral(t))
// Reference the count in WHERE
.where(master.type.eq(type_param).and(c.gt(0)))
EXISTS
方法肯定会优于 jOOQ 推荐的任何 COUNT(*) > 0
方法(如果您确实不需要预测确切的计数值)。