在 JOOQ 中使用 UNNEST select

Use UNNEST inside JOOQ's select

我有 SQL 喜欢:

select *
from some_table
where (select array(select unnest(first_array_field) except select unnest(second_array_field))) @> '{some_value}';

这是我尝试以 JOOQ 方式为该查询编写 where 条件:

  private Condition selectAwayValue(
      List<Long> list) {

    var allSelect = dslContext
        .select(TABLE.ARRAY_1)
        .from(DSL.unnest(TABLE.ARRAY_1));

    var homeSelect = dslContext
        .select(TABLE.ARRAY_2)
        .from(DSL.unnest(TABLE.ARRAY_2));

    var awaySelect = allSelect.except(homeSelect);

    var awayArray = dslContext.select(DSL.array(awaySelect));

    return awayArray.asField().contains(awayCompetitorIdsList);
  }

我在这里面临 2 个问题:

  1. 我得到的 SQL 与我预期的不同(见上文)
  2. 也遇到了像Cannot convert from 5 (class java.lang.Long) to class [Ljava.lang.Long;
  3. 这样的异常

我明白异常对我说的是什么,但不明白为什么:)

用 jooq 语法编写我的 SQL 的最佳方法是什么?

我用的是jooq最新稳定版,Postgres最新稳定版

谢谢

备选方案

如果你这样想你的问题:

select *
from some_table
where first_array_field @> '{some_value}'
and not second_array_field @> '{some_value}';

那么,这个问题在jOOQ中表达起来也简单多了

ctx.selectFrom(SOME_TABLE)
   .where(SOME_TABLE.FIRST_ARRAY_FIELD.contains(new Long[] { someValue }))
   .andNot(SOME_TABLE.SECOND_ARRAY_FIELD.contains(new Long[] { someValue }))
   .fetch();

为什么您的解决方案不起作用

当然,您可以使用自己的方法实现这一目标。关于您观察到的问题:

I got the different SQL than I expected (see above)

jOOQ 不支持将 UNNEST() 放入 SELECT 的语法。它在 PostgreSQL 中的语法也很奇怪,并且在很多方面都不像您想象的那样。您是否尝试过将 UNNEST() 的两个实例放入 SELECT 中?第二个不会像第一个那样形成笛卡尔积。它的行将按顺序与第一行匹配。

然而,在 FROM 中使用 UNNEST 是正确的,并且在本机 PostgreSQL 中也更直观,即使它更长一些。它得到了 jOOQ 的支持。

Also got the exception like Cannot convert from 5 (class java.lang.Long) to class [Ljava.lang.Long;

这是因为您似乎在调用 Field.contains() 时使用的是标量参数,而不是数组。请参阅 Javadoc 中的示例,或我上面的示例:

 // Use this expression
 val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })

 // ... to render this SQL
 ARRAY[1, 2, 3] @> ARRAY[1, 2]

不过,我认为我的替代方法要简单得多。