Это то, что я называю TOP N на запрос категории , где N = 1
.
Использование стандарта SQL LATERAL
Самым простым решением с использованием SQL является использование стандарта SQL LATERAL
в PostgreSQL, Oracle, DB2 или APPLY
в SQL Server, Oracle.Вот версия 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 рейтинг TOP 1 для каждой категории может бытьнаписано также с использованием DISTINCT ON
, которое зависит от поставщика для 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 со связями в результате, то использование функции RANK()
в PostgreSQL неизбежно.
Решение с использованием оконных функций также обсуждалось в ранее связанном блоге.post
Примечание
Весь приведенный выше код jOOQ предполагает наличие статического импорта на месте:
import static org.jooq.impl.DSL.*;