#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 проблемами:
- Я получил другой SQL, чем ожидал (см. Выше).
- Также есть исключение, как
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]
Но опять же, я думаю, что мой альтернативный подход намного проще.