Jooq ERROR: missing FROM-clause entry for table for nested query(sum and group by)
Jooq ERROR: missing FROM-clause entry for table for nested query(sum and group by)
我在 Postgres 9.6 上执行了以下 jooq 语句:
DSLContext context = DSL.using(connection, POSTGRES_10);
testSafesFundsAllocationRecord record =
context.select()
.from(
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))
.where(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT.greaterOrEqual(amount))
.and(TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID.notIn(excludedLedgers))
.orderBy(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT.asc())
.limit(1)
.fetchOne()
.into(TEST_SAFES_FUNDS_ALLOCATION);
翻译如下:
SQL [
select "alias_88420990"."ledger_id", "alias_88420990"."amount" 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"
where ("public"."test_safes_funds_allocation"."amount" >= ? and 1 = 1) order by "public"."test_safes_funds_allocation"."amount" asc limit ?];
excludedLedgers -> 是一个空字符串数组
结果是:
org.postgresql.util.PSQLException: ERROR: missing FROM-clause entry for table "test_safes_funds_allocation"
Position: 334
谁能告诉我查询中的问题是什么?如您所见,它是嵌套的...但我似乎无法理解这个问题。
查询执行以下操作:
对同一分类帐 id(分组依据)的所有数量行求和,然后从输出 return 数量大于变量数量的最小行,我们可以通过数组排除特定的 ledger_id
(它是在此示例中为空)。
任何帮助将不胜感激,
此致
未命名派生 table 仅在少数 SQL 方言(例如 Oracle)中受支持,而不是在所有方言中(例如在 PostgreSQL 中不支持)。这就是为什么 jOOQ 会为每个派生的 table 生成一个别名。现在您的派生 table 已使用别名,您无法再使用原始 table 名称访问其列,但您必须改用别名。您可以在生成的 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 查询可以这样重写,以获得正确的 table 名称:
// 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)
从别名 table 中提取字段,而不会丢失类型信息。
改进修复,利用现有 table 类型
鉴于你的派生有两列,其名称也出现在原始 table 中,你可以使用 "trick" 从 jOOQ API 中获得更多类型安全,并且因此,这是一种取消引用列的更方便的方法。首先为 table 添加别名:
// 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();
记住,这是一个技巧,只有派生的 table 的列与派生的 table 的原始 table 具有相同的名称和类型时才有效选择自。
重写你的SQL
Derived tables(和常见的 table 表达式)是 jOOQ 的 DSL 不如原生 SQL 强大的领域,因为 jOOQ 无法轻松地对派生 table 以通常的方式。这就是必须使用局部变量和类型不安全取消引用的原因。
通常,如果这是一个选项,这个警告是完全避免派生 table 的充分理由。在您的情况下,您不需要派生 table。更好的查询(在本机 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()
我在 Postgres 9.6 上执行了以下 jooq 语句:
DSLContext context = DSL.using(connection, POSTGRES_10);
testSafesFundsAllocationRecord record =
context.select()
.from(
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))
.where(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT.greaterOrEqual(amount))
.and(TEST_SAFES_FUNDS_ALLOCATION.LEDGER_ID.notIn(excludedLedgers))
.orderBy(TEST_SAFES_FUNDS_ALLOCATION.AMOUNT.asc())
.limit(1)
.fetchOne()
.into(TEST_SAFES_FUNDS_ALLOCATION);
翻译如下:
SQL [
select "alias_88420990"."ledger_id", "alias_88420990"."amount" 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"
where ("public"."test_safes_funds_allocation"."amount" >= ? and 1 = 1) order by "public"."test_safes_funds_allocation"."amount" asc limit ?];
excludedLedgers -> 是一个空字符串数组
结果是:
org.postgresql.util.PSQLException: ERROR: missing FROM-clause entry for table "test_safes_funds_allocation"
Position: 334
谁能告诉我查询中的问题是什么?如您所见,它是嵌套的...但我似乎无法理解这个问题。
查询执行以下操作:
对同一分类帐 id(分组依据)的所有数量行求和,然后从输出 return 数量大于变量数量的最小行,我们可以通过数组排除特定的 ledger_id
(它是在此示例中为空)。
任何帮助将不胜感激,
此致
未命名派生 table 仅在少数 SQL 方言(例如 Oracle)中受支持,而不是在所有方言中(例如在 PostgreSQL 中不支持)。这就是为什么 jOOQ 会为每个派生的 table 生成一个别名。现在您的派生 table 已使用别名,您无法再使用原始 table 名称访问其列,但您必须改用别名。您可以在生成的 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 查询可以这样重写,以获得正确的 table 名称:
// 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)
从别名 table 中提取字段,而不会丢失类型信息。
改进修复,利用现有 table 类型
鉴于你的派生有两列,其名称也出现在原始 table 中,你可以使用 "trick" 从 jOOQ API 中获得更多类型安全,并且因此,这是一种取消引用列的更方便的方法。首先为 table 添加别名:
// 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();
记住,这是一个技巧,只有派生的 table 的列与派生的 table 的原始 table 具有相同的名称和类型时才有效选择自。
重写你的SQL
Derived tables(和常见的 table 表达式)是 jOOQ 的 DSL 不如原生 SQL 强大的领域,因为 jOOQ 无法轻松地对派生 table 以通常的方式。这就是必须使用局部变量和类型不安全取消引用的原因。
通常,如果这是一个选项,这个警告是完全避免派生 table 的充分理由。在您的情况下,您不需要派生 table。更好的查询(在本机 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()