Я пытаюсь выразить следующий SQL в JOOQ. Тем не менее, я либо имеют огромные проблемы с типами с использованием производных таблиц или я получаю то, что компилирует, но либо терпит неудачу на уровне SQL или даже в JAVA. Может кто-нибудь дать мне представление о том, как правильно использовать производные таблицы в этом контексте?
SELECT
id,
ROUND(num_realized / num_requirements, 2) AS realized_percent,
ROUND(num_requirements / max_req, 2) AS activity_percent
FROM (
SELECT
requirement.project_id AS id,
COUNT(requirement.id) AS num_requirements,
COUNT(requirement.realized) AS num_realized
FROM
requirement
GROUP BY
requirement.project_id) AS stats
CROSS JOIN (
SELECT
MAX(num_requirements) AS max_req
FROM (
SELECT
requirement.project_id AS id,
COUNT(requirement.id) AS num_requirements,
COUNT(requirement.realized) AS num_realized
FROM
requirement
GROUP BY
requirement.project_id) AS stats) AS req_max
Оператор работает отлично, когда применяется в SQL, но я не могу получить это выражение в JOOQ.
Моя последняя попытка была с помощью
Table<Record3<Integer, Integer, Integer>> stats =
DSL.select(
REQUIREMENT.PROJECT_ID.as("id"),
DSL.count(REQUIREMENT.ID).as("num_requirements"),
DSL.count(REQUIREMENT.REALIZED).as("num_realized")
).from(REQUIREMENT).groupBy(REQUIREMENT.PROJECT_ID).asTable("stats");
Table<Record2<Integer, Integer>> req_max =
DSL.select(
stats.field(0),
DSL.min(stats.field(1))
)
.from(stats).asTable("req_max");
Однако я получаю сообщение об ошибке: несовместимые типы:
Table<Record2<CAP#1,CAP#2>> cannot be converted to Table<Record2<Integer,Integer>>
Я перепробовал кучу различных методов, включая определение типа данных, и с помощью .поля (String, Тип данных), вместо того, чтобы использовать «Records», но все, что я делаю, его либо не компиляции или не во время выполнения в неизвестной ошибке.
Я был бы рад за любую помощь.
Использование функций окна вместо
В общем, Самосоединения следует избегать, когда вы можете. Во многих случаях, оконные функции могут решить проблему гораздо элегантнее, чем в агрегатах вложенных запросов. Если вы используете MySQL 8, ваш запрос может быть переписан как:
SELECT
requirement.project_id AS id,
ROUND(COUNT(requirement.realized) / COUNT(requirement.id), 2) AS realized_percent,
ROUND(COUNT(requirement.id) / MAX(COUNT(requirement.id)) OVER(), 2) AS activity_percent
FROM
requirement
GROUP BY
requirement.project_id
Обратите внимание на MAX(..) OVER()
оконную функцию, которая может агрегировать обычные функции агрегирования , как описано здесь . Я знаю , что вы используете MySQL 5.7, которая не имеет функцию окна поддержки пока нет, но для полноты, этот ответ требует решений на основе функции окна - может быть , как мотивация для обновления :-)
Много сложных jOOQ запросов можно упростить, сделав основной SQL запрос проще в первую очередь.
Выведенная проблема таблицы вы столкнулись с
Проблема в том , ваше использование stats.field(0)
и stats.field(1)
. Метод подписи
Field<?> field(int index)
Там нет никакого способа jOOQ может предоставить вам безопасность типа при доступе столбцов таблицы по индексу, следовательно , типа возвращаемого значения Field<?>
, где тип столбца является родовым джокер. Есть несколько решений здесь:
- Избегайте типобезопасность , если вам не нужен. Вы всегда можете объявить таблицу
Table<?> req_max
. Из только вашего примера, я не уверен , что если вам нужна типобезопасность здесь Извлечение ваших ссылок на поля в качестве локальных переменных. Вместо вложения , например , в
id
столбец в вашейstats
таблице, почему нет:Field<Integer> id = REQUIREMENT.PROJECT_ID.as("id"); Field<Integer> numRequirements = DSL.count(REQUIREMENT.ID).as("num_requirements"); Field<Integer> numRealized = DSL.count(REQUIREMENT.REALIZED).as("num_realized");
а затем использовать его как это:
var stats = DSL.select(id, numRequirements, numRealized) .from(REQUIREMENT) .groupBy(REQUIREMENT.PROJECT_ID) .asTable("stats"); var reqMax = DSL.select(stats.field(id), DSL.max(stats.field(numRequirements))) .from(stats) .asTable(reqMax);