Currently I am using the latest jOOQ 3.19.5(R2dbc/Postgres) in my project.
I encountered an issue like this.
Given master and details` table.
|master |
id,
type
|details|
id,
master_id,
other_id // connect other tables.
I want to query master and details together with the following condition from external parameters:
- master type
- details other_id
I tried to use the following query clause:
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))
But this query will includes all masters that type is type_param with some empty details.
I try to add a count subselect clause as field to filter out result like this.
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)))
It doesn't work, and report error in the generated SQL:
column "details_count" does not exist
When I added an exists to where, it works.
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))
)
Is there a better SQL to select the master/details in one query and filter by the detail's property?
You cannot filter anything using
WHEREthat you've projected in theSELECTclause due to the logical order of operations in SQL.In order to make your
COUNT(*)value available to yourWHEREclause, you have to push it into theFROMclause, e.g. by using a derived table, or by usingLATERAL- in your particular case it would work. I've described this technique also here, whereLATERALis used to create "local column variables" in SQLE.g. this could work:
Note though that your
EXISTSapproach will certainly outperform anyCOUNT(*) > 0approach as also recommended by jOOQ (if you don't really need to project the exact count value).