Как выбрать одну строку из набора результатов для одного поля? - PullRequest
0 голосов
/ 04 октября 2018

Мой запрос на выбор:

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.ИМЯ от всех их в ResultSet.

1 Ответ

0 голосов
/ 09 октября 2018

Это то, что я называю 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.*;
...