Безымянные производные таблицы поддерживаются только в нескольких диалектах SQL (например, Oracle), но не во всех (например, не в PostgreSQL).Вот почему jOOQ генерирует вам псевдоним для каждой производной таблицы.Теперь, когда ваша производная таблица имеет псевдоним, вы больше не можете обращаться к ее столбцам, используя исходные имена таблиц, но вы должны использовать псевдоним вместо этого.Вы можете увидеть, где это пошло не так в вашем сгенерированном SQL-запросе:
select
"alias_88420990"."ledger_id", -- These are correctly referenced, because you used
"alias_88420990"."amount" -- select(), so jOOQ did the dereferencing for your
from (
select
"public"."test_safes_funds_allocation"."ledger_id",
sum("public"."test_safes_funds_allocation"."amount") as "amount"
from "public"."test_safes_funds_allocation"
group by "public"."test_safes_funds_allocation"."ledger_id"
) as "alias_88420990" -- This alias is generated by jOOQ
-- In these predicates, you're referencing the original column name with full qualification
-- when you should be referncing the column from alias_88420990 instead
where ("public"."test_safes_funds_allocation"."amount" >= ? and 1 = 1)
order by "public"."test_safes_funds_allocation"."amount" asc
limit ?
Каноническое исправление
Таким образом, ваш запрос jOOQ можно переписать так, чтобы получить правильные имена таблиц:
// Create a local variable to contain your subquery. Ideally, provide an explicit alias
Table<?> t = table(
select(
TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID,
sum(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT)
.as(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT))
.from(TEST_SAFES_FUNDS_ALLOCATION)
.groupBy(TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID)).as("t");
// Now, use t everywhere, instead of TEST_SAFES_FUNDS_ALLOCATION
context.select()
.from(t)
.where(t.field(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT).greaterOrEqual(amount))
.and(t.field(TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID).notIn(excludedLedgers))
.orderBy(t.field(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT).asc())
.limit(1)
.fetchOne();
Я использую Table.field(Field)
для извлечения поля из таблицы с псевдонимами без потери информации о типах.
Улучшенное исправление, использующее существующие типы таблиц
Учитывая, что у вашего производного есть два столбца, имена которых также указаны в исходной таблице, вы можете использовать "хитрость", чтобы повысить безопасность типов из API jOOQ и, таким образом, более удобный способ разыменования столбцов.Псевдоним таблицы сначала:
// This t reference now has all the column references like the original table
TestSafesFundsAllocation t = TEST_SAFES_FUNDS_ALLOCATION.as("t");
// The subquery is also named "t", but has a different definition
Table<?> subquery = table(
select(
TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID,
sum(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT)
.as(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT))
.from(TEST_SAFES_FUNDS_ALLOCATION)
.groupBy(TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID)).as(t);
// Now, select again from the subquery, but dereference columns from the aliased table t
context.select()
.from(subquery)
.where(t.AMOUNT.greaterOrEqual(amount))
.and(t.LEDGER_ID.notIn(excludedLedgers))
.orderBy(t.AMOUNT.asc())
.limit(1)
.fetchOne();
Помните, что это хитрость, которая работает только до тех пор, пока столбцы производной таблицы имеют те же имена и типы, что и исходная таблица, из которой выбирается производная таблица.
Переписать ваш SQL
Производные таблицы (и общие выражения таблиц) - это область, в которой DSL в jOOQ не так мощен, как собственный SQL, поскольку jOOQ не может легко проверить тип производной таблицы обычным способом.Вот почему необходимо использовать локальные переменные и небезопасную разыменование.
Часто это предостережение является достаточно веской причиной, чтобы полностью избегать производных таблиц, если это вариант.В вашем случае вам не нужна производная таблица.Лучший запрос (даже лучше в нативном SQL) будет выглядеть так:
context.select(
TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID,
sum(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT).as(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT))
.from(TEST_SAFES_FUNDS_ALLOCATION)
.where(TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID.notIn(excludedLedgers))
.groupBy(TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID)
.having(sum(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT).greaterOrEqual(amount))
.orderBy(sum(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT).asc())
.limit(1)
.fetchOne()