jOOQ - 分组依据使用别名而不是列
jOOQ - group by uses alias instead of columns
我是运行 jOOQ 3.13.6,在Oracle 11g springboot 环境上。
要使用 listagg 函数,我正在尝试此处提供的解决方案:
示例代码:
@Autowired
private DSLContext dsl;
// setting tables
Table table1 = DSL.table("table_1").as("t1");
Table table2 = DSL.table("table_2").as("t2");
// creating fields
final List<Field<?>> fields = new ArrayList<Field<?>>();
fields.add(DSL.field(DSL.name("t1", "t1_id")).as("id"));
Field cf = DSL.field(DSL.name("t2", "t2_code")).as("code");
fields.add(listAgg(cf, ";", null)); // no order
// running query
dsl.settings().withRenderQuotedNames(RenderQuotedNames.EXPLICIT_DEFAULT_UNQUOTED);
dsl.select(fields)
.from(table1)
.join(table2).on("t1.t1_id = t2.t1_id")
.where("t1.t1_id = ?", id)
.groupBy(fields)
但是,它执行以下查询:
select t1.t1_id id,
listagg(t2.t2_code) within group (null) as code
from table_1 t1
join table_2 t2 on ( t1.t1_id = t2.t2_id )
where t1.t1_id = 1
group by id
group by 应使用原始列名称 (t1.t1_id),而不是别名。
请注意,为了这个答案,并且为了简洁起见,我假设您一直在使用 code generator。没有使用代码生成,答案是一样的。
为什么现在的行为?
Note, this behaviour is also documented here in the manual.
在 jOOQ 中,别名列表达式 T1.T1_ID.as("id")
只能生成其自身的 2 个不同版本:
T1.T1_ID as ID
,即别名声明(在 SELECT
内部时,在顶层)
ID
,即别名引用(当位于 SELECT
子句以外的任何其他子句/表达式内时)
没有生成的第三种类型 SQL 取决于您嵌入别名表达式的位置,例如当您将表达式放在 WHERE
或 GROUP BY
等中时,无别名的列表达式 T1.T1_ID
。基本原理很简单。用户在编写时会期望什么:
groupBy(T1.T1_ID.as("id"))
为什么他们期望 as()
调用是 no-op?那会比现状更令人惊讶。
与其他渲染模式的一致性
jOOQ 中还有其他类型的 QueryPart
,它们具有类似的别名功能:
Field
Table
WindowSpecification
Parameter
CTE
让我们看一下 CTE 示例:
Table<?> cte = name("cte").as(select(...))
cte
引用有 2 种渲染模式 SQL:
- CTE 声明(如果放在
WITH
子句中)
- CTE 参考(如果放在
FROM
等)
我认为您不会期望 cte
引用忽略别名,只渲染 SELECT
本身?
同样使用 table 别名:
T1 x = T1.as("x");
这可以呈现为:
- 别名声明(如果放在
FROM
子句中)
- 别名引用
因为 FROM
子句是 logically before 任何其他子句,你永远不会期望你的 x
引用只呈现 T1
,而不是 x
或 T1 as x
,对吗?
因此,出于 jOOQ API 一致性的原因,Field
别名的行为也必须与所有其他别名一样。
该怎么做?
不要 re-use 别名表达式位于 SELECT
子句之外。写 jOOQ SQL 就像你写实际的 SQL:
ctx.select(T1.T1_ID.as("id"), ...)
.from(T1)
.groupBy(T1.T1_ID)
...
我是运行 jOOQ 3.13.6,在Oracle 11g springboot 环境上。
要使用 listagg 函数,我正在尝试此处提供的解决方案:
示例代码:
@Autowired
private DSLContext dsl;
// setting tables
Table table1 = DSL.table("table_1").as("t1");
Table table2 = DSL.table("table_2").as("t2");
// creating fields
final List<Field<?>> fields = new ArrayList<Field<?>>();
fields.add(DSL.field(DSL.name("t1", "t1_id")).as("id"));
Field cf = DSL.field(DSL.name("t2", "t2_code")).as("code");
fields.add(listAgg(cf, ";", null)); // no order
// running query
dsl.settings().withRenderQuotedNames(RenderQuotedNames.EXPLICIT_DEFAULT_UNQUOTED);
dsl.select(fields)
.from(table1)
.join(table2).on("t1.t1_id = t2.t1_id")
.where("t1.t1_id = ?", id)
.groupBy(fields)
但是,它执行以下查询:
select t1.t1_id id,
listagg(t2.t2_code) within group (null) as code
from table_1 t1
join table_2 t2 on ( t1.t1_id = t2.t2_id )
where t1.t1_id = 1
group by id
group by 应使用原始列名称 (t1.t1_id),而不是别名。
请注意,为了这个答案,并且为了简洁起见,我假设您一直在使用 code generator。没有使用代码生成,答案是一样的。
为什么现在的行为?
Note, this behaviour is also documented here in the manual.
在 jOOQ 中,别名列表达式 T1.T1_ID.as("id")
只能生成其自身的 2 个不同版本:
T1.T1_ID as ID
,即别名声明(在SELECT
内部时,在顶层)ID
,即别名引用(当位于SELECT
子句以外的任何其他子句/表达式内时)
没有生成的第三种类型 SQL 取决于您嵌入别名表达式的位置,例如当您将表达式放在 WHERE
或 GROUP BY
等中时,无别名的列表达式 T1.T1_ID
。基本原理很简单。用户在编写时会期望什么:
groupBy(T1.T1_ID.as("id"))
为什么他们期望 as()
调用是 no-op?那会比现状更令人惊讶。
与其他渲染模式的一致性
jOOQ 中还有其他类型的 QueryPart
,它们具有类似的别名功能:
Field
Table
WindowSpecification
Parameter
CTE
让我们看一下 CTE 示例:
Table<?> cte = name("cte").as(select(...))
cte
引用有 2 种渲染模式 SQL:
- CTE 声明(如果放在
WITH
子句中) - CTE 参考(如果放在
FROM
等)
我认为您不会期望 cte
引用忽略别名,只渲染 SELECT
本身?
同样使用 table 别名:
T1 x = T1.as("x");
这可以呈现为:
- 别名声明(如果放在
FROM
子句中) - 别名引用
因为 FROM
子句是 logically before 任何其他子句,你永远不会期望你的 x
引用只呈现 T1
,而不是 x
或 T1 as x
,对吗?
因此,出于 jOOQ API 一致性的原因,Field
别名的行为也必须与所有其他别名一样。
该怎么做?
不要 re-use 别名表达式位于 SELECT
子句之外。写 jOOQ SQL 就像你写实际的 SQL:
ctx.select(T1.T1_ID.as("id"), ...)
.from(T1)
.groupBy(T1.T1_ID)
...