如何从结果集中为一个字段选择单行?

时间:2018-10-04 08:09:01

标签: java postgresql jooq

我的选择查询是:

sql.select(COMPANY.NAME, COMPANY_CONTACT.NAME.as("CONTACT_INTERACTION"))
                .from(COMPANY)
                .join(COMPANY_CONTACT)
                    .on(COMPANY_CONTACT.COMPANY_ID.equal(COMPANY.ID))
.where(COMPANY.DELETED.equal(false));

'sql'的类型为 DSLContext

我试图从结果集中的所有这些中选择一个 COMPANY_CONTACT.NAME

1 个答案:

答案 0 :(得分:0)

这就是我所说的TOP N per category query,其中N = 1

使用SQL标准LATERAL

使用SQL的最简单解决方案是在PostgreSQL,Oracle,DB2中使用SQL标准LATERAL,在SQL Server,Oracle中使用APPLY。这是PostgreSQL版本:

SELECT
  c.name,
  cc.name AS contact_interaction
FROM company AS c
CROSS JOIN LATERAL (
  SELECT cc.name
  FROM company_contact cc
  WHERE cc.company_id = c.id
  ORDER BY cc.follow_up DESC
  LIMIT 1
) AS cc 
WHERE NOT c.deleted

或与jOOQ:

sql.select(COMPANY.NAME, COMPANY_CONTACT.NAME.as("CONTACT_INTERACTION"))
   .from(COMPANY)
   .crossJoin(lateral(table(
        select(COMPANY_CONTACT.NAME)
       .from(COMPANY_CONTACT)
       .where(COMPANY_CONTACT.COMPANY_ID.eq(COMPANY.ID))
       .orderBy(COMPANY_CONTACT.FOLLOW_UP.desc())
       .limit(1)
   ).as(COMPANY_CONTACT)))
   .where(not(COMPANY.DELETED))
   .fetch();

使用特定于PostgreSQL的DISTINCT ON

在PostgreSQL中,也可以使用DISTINCT ON来编写每个类别查询的TOP 1,这是PostgreSQL的特定于供应商,并且受jOOQ支持:

SELECT DISTINCT ON (c.company_id) c.name, cc.name AS contact_interaction
FROM company AS c
JOIN company_contact AS cc
ON cc.company_id = c.id
WHERE NOT c.deleted
ORDER BY c.company_id, cc.follow_up DESC

或者在jOOQ中

sql.selectDistinct(COMPANY.NAME, COMPANY_CONTACT.NAME.as("CONTACT_INTERACTION"))
   .on(COMPANY.COMPANY_ID)
   .from(COMPANY)
   .join(COMPANY_CONTACT)
   .on(COMPANY_CONTACT.COMPANY_ID.eq(COMPANY.ID))
   .where(not(COMPANY.DELETED))
   .orderBy(COMPANY.COMPANY_ID, COMPANY_CONTACT.FOLLOW_UP.desc())
   .fetch();

使用窗口功能

同样可以使用窗口函数来实现相同的功能,但是它比上面的解决方案要简单。但是,如果您希望结果中的TOP 1联系紧密,那么在PostgreSQL中不可避免地使用RANK()函数。

A solution using window functions is also discussed in the previously linked blog post

注意

以上所有jOOQ代码均假定您已将此静态导入就位:

import static org.jooq.impl.DSL.*;