jOOQ - 在查询中简洁地表示列和聚合/窗口函数

Posted

技术标签:

【中文标题】jOOQ - 在查询中简洁地表示列和聚合/窗口函数【英文标题】:jOOQ - Concisely Representing Both Columns and Aggregate/Window Functions in a Query 【发布时间】:2014-10-08 10:22:22 【问题描述】:

这篇文章是我在一个类似问题上发表评论的结果:https://***.com/a/19860271/2308858

我正在使用 PostgreSQL 和 jOOQ 3.4 并尝试在 jOOQ 中表示以下 SQL 查询:

SELECT *, COUNT(*) OVER() 
FROM table1 t1
JOIN table2 t2 ON (t1.id = t2.id)
JOIN table3 t3 ON (t1.otherId = t3.otherId)

我喜欢 Postgres 让我用SELECT *, COUNT(*) OVER() 简洁地表示“所有列加上count 列”。但是当我尝试在 jOOQ 中表示同样的查询时,我能做的最简洁的方法是:

create.select( TABLE1.fields() ).select( TABLE2.fields() ).select( TABLE3.fields() ).select( count().over() )
   .from( TABLE1 )
   .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
   .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))

理想情况下,我会这样写:

create.select().select( count().over() )
   .from( TABLE1 )
   .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
   .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))

但这似乎不起作用。关于如何做到这一点的任何想法?

【问题讨论】:

【参考方案1】:

您自己发现的这个解决方案确实是使用 jOOQ API 的方法:

create.select( TABLE1.fields() )
      .select( TABLE2.fields() )
      .select( TABLE3.fields() )
      .select( count().over() )
      ...

它在概念上对应于这个有效的 SQL 查询:

SELECT table1.*, table2.*, table3.*, COUNT(*) OVER()
...

操作 jOOQ“模型 API”:

但是,如果这让您感到厌烦,您也可以通过以下小技巧解决此问题:

// Get access to the "model API" from a statement without any SELECT fields
SelectQuery<?> select =
create.select()
      .from( TABLE1 )
      .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
      .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))
      .getQuery();

// Copy all fields from the SELECT statement:
List<Field<?>> fields = new ArrayList<>(select.getSelect());

// And explicitly add them:
select.addSelect(fields);
select.addSelect(count().over());

这与您最初的尝试一样冗长,但通常使用起来可能更简单一些。

使用派生表

当然,您也可以简单地编写以下等效的 SQL 查询,这将是更标准的 SQL:

SELECT t.*, COUNT(*) OVER()
FROM (
  SELECT *
  FROM table1 t1
  JOIN table2 t2 ON (t1.id = t2.id)
  JOIN table3 t3 ON (t1.otherId = t3.otherId)
) t

使用 jOOQ,这将转化为:

Table<?> t = select()
            .from( TABLE1 )
            .join( TABLE2 ).on( TABLE1.ID.equal( TABLE2.ID ))
            .join( TABLE3 ).on( TABLE1.OTHER_ID.equal( TABLE3.OTHER_ID ))
            .asTable("t");

create.select(t.fields(), count().over())
      .from(t);

支持星号

在 jOOQ 的未来版本中,the actual asterisk (*) might be supported explicitly through the jOOQ API。不过,目前还不清楚如何在语法上实现这一点。

附注:

我一直很好奇 PostgreSQL 在这里允许这种语法:

SELECT *, COUNT(*) OVER() 
...

SQL 引擎几乎不支持它,而且有点“不可预测”。 SQL 标准也不允许将“独立星号”与其他列表达式组合。

【讨论】:

感谢您的澄清,卢卡斯!由于我没有在多个位置重用此字段,因此听起来原始语法是最好的。很高兴知道桌面上的其他选项。

以上是关于jOOQ - 在查询中简洁地表示列和聚合/窗口函数的主要内容,如果未能解决你的问题,请参考以下文章

为啥 CROSS APPLY 与列和聚合函数需要 Group by

SQL Server中的开窗函数是啥?

使用 jOOQ 创建自定义聚合函数

SQL函数

Oracl Over函数

在子查询中使用聚合和窗口函数