JOOQ Производные таблицы

user3567992:

Я пытаюсь выразить следующий 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», но все, что я делаю, его либо не компиляции или не во время выполнения в неизвестной ошибке.

Я был бы рад за любую помощь.

Lukas Эдер:

Использование функций окна вместо

В общем, Самосоединения следует избегать, когда вы можете. Во многих случаях, оконные функции могут решить проблему гораздо элегантнее, чем в агрегатах вложенных запросов. Если вы используете 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<?>, где тип столбца является родовым джокер. Есть несколько решений здесь:

  1. Избегайте типобезопасность , если вам не нужен. Вы всегда можете объявить таблицу Table<?> req_max. Из только вашего примера, я не уверен , что если вам нужна типобезопасность здесь
  2. Извлечение ваших ссылок на поля в качестве локальных переменных. Вместо вложения , например , в 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);
    

рекомендация

отhttp://10.200.1.11:23101/article/api/json?id=478588&siteId=1
рекомендация