前面的问题介绍了如何使用 jOOQ 的 MULTISET_AGG
功能根据嵌套集合上的聚合函数对查询进行排序:使用 GROUP BY
按父表中的所有选定列对查询进行分组,而不是尝试利用 MULTISET
的实现细节。
有没有一种方法可以处理多级集合?我正在使用PostgreSQL,但显然如果有一种独立于引擎的方法来做到这一点,那就更好了。
例如,如果我有一个使用MULTISET
的嵌套查询:
var results =
create
.select(
ORGANIZATIONS.ID,
ORGANIZATIONS.NAME,
multiset(
select(
DEPARTMENTS.ID,
DEPARTMENTS.NAME,
multiset(
select(EMPLOYEES.ID, EMPLOYEES.SALARY, EMPLOYEES.NAME)
.from(EMPLOYEES)
.where(EMPLOYEES.DEPARTMENT_ID.eq(DEPARTMENTS.ID)))))
.from(DEPARTMENTS)
.where(DEPARTMENTS.ORGANIZATION_ID.eq(ORGANIZATIONS.ID)))
.from(ORGANIZATIONS)
.fetch();
如果我在最里面的查询中输入ORDERBY
,我可以很容易地按薪资对每个部门的员工进行排序。
multiset(
select(EMPLOYEES.ID, EMPLOYEES.SALARY, EMPLOYEES.NAME)
.from(EMPLOYEES)
.where(EMPLOYEES.DEPARTMENT_ID.eq(DEPARTMENTS.ID))
.orderBy(EMPLOYEES.SALARY.desc()))))
但是我如何根据最高员工工资对部门列表进行排序,以及按部门最高员工工资对组织列表进行排序?
将MULTISET
s更改为MULTISET_AGG
s,并且只在查询的顶层执行ORDER BY
,就像前面的问题中只有一个嵌套级别一样,似乎它不能在这里工作,因为您需要同时按两组不同的列进行分组,也因为您不能嵌套聚合函数(至少在PostgreSQL上是这样)。
我想不出一个简单的方法来汇总这些总和而不访问某些表两次。如果我这样做了,我会更新这个答案。但是这里有一个解决方案来回答你的问题:
var results = create
.select(
ORGANIZATIONS.ID,
ORGANIZATIONS.NAME,
multiset(
select(
DEPARTMENTS.ID,
DEPARTMENTS.NAME,
// Employees per department sorted by salary
multisetAgg(EMPLOYEES.ID, EMPLOYEES.SALARY, EMPLOYEES.NAME)
.orderBy(EMPLOYEES.SALARY.desc()))
.from(DEPARTMENTS)
.leftJoin(EMPLOYEES)
.on(EMPLOYEES.DEPARTMENT_ID.eq(DEPARTMENTS.ID))
.where(DEPARTMENTS.ORGANIZATION_ID.eq(ORGANIZATIONS.ID))
.groupBy(DEPARTMENTS.ID, DEPARTMENTS.NAME)
// Departments sorted by max employee salary
.orderBy(max(EMPLOYEES.SALARY).desc()))
.from(ORGANIZATIONS)
// Organisations sorted by max employee salary via extra join
.orderBy(field(
select(max(EMPLOYEES.SALARY))
.from(EMPLOYEES)
.where(EMPLOYEES.departments().ORGANIZATION_ID.eq(ORGANIZATION.ID))
).desc())
.fetch();
另一种解决方案是仅在查询后对外部结果进行排序:
var results = create
.select(
ORGANIZATIONS.ID,
ORGANIZATIONS.NAME,
multiset(
select(
DEPARTMENTS.ID,
DEPARTMENTS.NAME,
multisetAgg(EMPLOYEES.ID, EMPLOYEES.SALARY, EMPLOYEES.NAME)
.orderBy(EMPLOYEES.SALARY.desc()),
max(EMPLOYEES.SALARY))
.from(DEPARTMENTS)
.leftJoin(EMPLOYEES)
.on(EMPLOYEES.DEPARTMENT_ID.eq(DEPARTMENTS.ID))
.where(DEPARTMENTS.ORGANIZATION_ID.eq(ORGANIZATIONS.ID))
.groupBy(DEPARTMENTS.ID, DEPARTMENTS.NAME)
.orderBy(max(EMPLOYEES.SALARY).desc()))
.from(ORGANIZATIONS)
.fetch()
.sortDesc(Comparator.comparing(
// r.value3() is the outer multiset()
r -> r.value3().isEmpty()
? 0
// r.value3().get(0).value4() is the top max(EMPLOYEES.SALARY) value
: r.value3().get(0).value4()
));
可以定义一个新的运算符,再次从MULTISET
中提取一个值,而不依赖于它的SQL/XML或SQL/JSON序列化实现。或者,您可以使用普通的SQL模板滚动自己的,知道序列化实现是什么样子的(知道它将来可能会发生微妙的变化)