jOOQ 按详细信息属性选择主详细信息过滤器

问题描述 投票:0回答:1

目前我在我的项目中使用最新的jOOQ 3.19.5(R2dbc/Postgres)。

我也遇到过这样的问题。

给出

master
和详细信息表。

|master |
id, 
type 

|details| 
id, 
master_id, 
other_id // connect other tables.

我想从外部参数中查询主表和详细信息以及以下条件:

  • 大师型
  • 详细信息other_id

我尝试使用以下查询子句:

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
的属性进行过滤?

postgresql kotlin jooq r2dbc
1个回答
0
投票

由于 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
方法
(如果您确实不需要预测确切的计数值)。

© www.soinside.com 2019 - 2024. All rights reserved.