Используйте UNNEST внутри выбора JOOQ

#java #sql #postgresql #jooq

Вопрос:

У меня есть SQL, как:

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

Это моя попытка написать where условие для этого запроса в стиле JOOQ:

   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;

Я понимаю, что мне говорят исключения, но не понимаю, почему 🙂

Каков был бы лучший способ написать мой SQL в синтаксисе jooq?

Я использую последнюю стабильную версию jooq, последнюю стабильную версию Postgres

Спасибо

Ответ №1:

Альтернативное решение

Если вы думаете о своей проблеме таким образом:

 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();
 

Почему ваше решение не сработало

Конечно, вы могли бы справиться с этим, используя свой собственный подход. Относительно проблем, которые вы наблюдали:

Я получил другой SQL, чем ожидал (см. Выше).

Этот синтаксис, в который вы вводите UNNEST() , SELECT не поддерживается jOOQ. Это довольно странный синтаксис и в PostgreSQL, и во многих отношениях он не делает того, что вы могли бы подумать. Вы пробовали вставить два экземпляра UNNEST() in SELECT ? Второй не будет образовывать декартово произведение, как первый. Строки из него будут сопоставлены с первыми строками по порядку.

Тем не менее, использование UNNEST in FROM является правильным и более интуитивно понятным в собственном PostgreSQL, даже если оно немного длиннее. И это поддерживается Джуком.

Также есть исключение, например, Не удается преобразовать из 5 (класс java.lang.Долго) в класс [Ljava.lang.Длинный;

Это происходит потому, что вы, похоже, вызываете 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]
 

Но опять же, я думаю, что мой альтернативный подход намного проще.