Как перевести следующий SQL в jOOQ

У меня есть следующее (немного сложное для меня) обновление MariaDB 10.6:

update survey_definition sd
    join (select si.survey_def_id, si.status, si.end_date
          from survey_instance si
          where si.survey_def_id = ?1
            and si.status not in (14)
          order by si.end_date desc
          limit 1) latest on sd.id = latest.survey_def_id
set sd.latest_result=latest.status,
    sd.latest_survey_end_date=latest.end_date;

Как превратить его в jOOQ DSL? Является ли это возможным?

Моя лучшая (незавершенная) попытка:

jOOQ версия: 3.12.1

Текст DSL:

dslContext.update(SURVEY_DEFINITION
    .join(dslContext.select (SURVEY._INSTANCE.SURVEY_DEFINITION_ID, SURVEY_INSTANCE.STATUS, SURVEY_INSTANCE.END_TIME_MILLIS)
        . from(SURVEY_INSTANCE) SelectJoinStep<Record3<String, ScanStatus, Long>>
        . where(SURVEY_INSTANCE.SURVEY_DEFINITION_ID.eq(definitionId)) SelectConditionStep<Record3<Sting, ScanStatus, Long>>
        . limit(1) SelectLimitPercentStep<Record3<Sting, ScanStatus, Long>>
        .on (SURVEY_INSTANCE.ID.eq(SURVEY_DEFINITION.ID))
    )

.on() сработало: «Cannot resolve method 'on' in '"SelectLimitPercentStep'».

UPD: Я придумал следующее решение:

        final Table<Record3<String, ScanStatus, Long>> latest = dslContext
            .select(SURVEY_INSTANCE.SURVEY_DEFINITION_ID, SURVEY_INSTANCE.STATUS, SURVEY_INSTANCE.END_TIME_MILLIS)
            .from(SURVEY_INSTANCE)
            .where(DSL.and(
                SURVEY_INSTANCE.SURVEY_DEFINITION_ID.eq(definitionId),
                SURVEY_INSTANCE.STATUS.notEqual(ScanStatus.DELETED))
            )
            .orderBy(SURVEY_INSTANCE.END_TIME_MILLIS.desc())
            .limit(1)
            .asTable("latest");
        dslContext.update(SURVEY_DEFINITION
                .join(latest)
                .on(latest.field(SURVEY_INSTANCE.SURVEY_DEFINITION_ID).eq(SURVEY_DEFINITION.ID)))
            .set(SURVEY_DEFINITION.LATEST_SCAN_STATUS, latest.field(SURVEY_INSTANCE.STATUS))
            .where(SURVEY_DEFINITION.ID.eq(definitionId))
            .execute();

Спасибо @LukasEder и @VonC за помощь и идеи.

@LukasEder У меня есть. Но я не понимаю, как это использовать.

Sebastian Lore 12.06.2023 15:30

Я имею в виду, что на скриншоте очевидная ошибка, но, может быть, у вас есть более конкретные вопросы?

Lukas Eder 12.06.2023 19:47
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
105
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Конкретная проблема на вашем снимке экрана заключается в том, что вы неправильно разместили закрывающую скобку:

.join(select(...).limit(1)).on(SURVEY_INSTANCE.ID.eq(SURVEY_DEFINITION.ID))

Вместо:

.join(select(...).limit(1).on(SURVEY_INSTANCE.ID.eq(SURVEY_DEFINITION.ID))

Это кажется короче и более точным, чем мой ответ (я не знал jooq, поэтому долго изучал его). Проголосовал.

VonC 12.06.2023 20:46
Ответ принят как подходящий

Предоставленный вами SQL-запрос представляет собой сложный оператор UPDATE с предложением JOIN для подзапроса. В jOOQ вы можете создавать такие запросы, используя метод update()DSLContext в сочетании с методами join() и on() для предложения соединения и методами set() для предложения обновления.

Чтобы избежать каких-либо проблем с читаемостью (например, неуместных скобок), вы можете разложить запрос.

Я предполагаю, что:

  • ваши таблицы survey_definition и survey_instance генерируются как SURVEY_DEFINITION и SURVEY_INSTANCE соответственно. Вам необходимо импортировать сгенерированные таблицы. Если они не генерируются, необходимо создать их вручную.
  • у вас есть DSLContext доступный как context.
  • ?1 в вашем исходном SQL — это параметр, который будет предоставлен позже. В jOOQ DSL я заменил это на param("?1", Integer.class).

Тогда код будет таким:

import static org.jooq.impl.DSL.*;
import static com.example.generated.Tables.*;

// Assuming the DSLContext is available as "context"

SurveyDefinition SD = SURVEY_DEFINITION.as("sd");
SurveyInstance SI = SURVEY_INSTANCE.as("si");

Field<Integer> surveyDefId = field(name("survey_def_id"), Integer.class);
Field<Integer> status = field(name("status"), Integer.class);
Field<Timestamp> endDate = field(name("end_date"), Timestamp.class);

Table<?> latest = context
    .select(SI.SURVEY_DEF_ID.as(surveyDefId), SI.STATUS.as(status), SI.END_DATE.as(endDate))
    .from(SI)
    .where(SI.SURVEY_DEF_ID.eq(param("?1", Integer.class)), SI.STATUS.notIn(14))
    .orderBy(SI.END_DATE.desc())
    .limit(1)
    .asTable("latest");

context.update(SD)
    .join(latest)
    .on(SD.ID.eq(latest.field(surveyDefId)))
    .set(SD.LATEST_RESULT, latest.field(status))
    .set(SD.LATEST_SURVEY_END_DATE, latest.field(endDate))
    .execute();

Примечание. В коде предполагается, что LATEST_RESULT и LATEST_SURVEY_END_DATE являются точными именами столбцов в вашей SURVEY_DEFINITION таблице и что их типы совпадают с типами из подзапроса. Если это не так, вам может потребоваться изменить эти имена или добавить преобразования типов.

Как видите, я использую метод on() (часть предложения ON для объекта TableOnStep , который возвращается вызовом join(latest).
Я не использую on() не для объекта SelectLimitPercentStep (у которого нет метода on(), отсюда и исходное сообщение об ошибке «Cannot resolve method 'on' in '"SelectLimitPercentStep'»).

context.update(SD)
    .join(latest)
    .on(SD.ID.eq(latest.field(surveyDefId)))
    ...

Здесь latest — это объект Table, представляющий производную таблицу.
Поэтому вызов on() в этом контексте не должен вызывать ошибку компиляции.


Почему-то не могу сделать джойн после context.update(SD), просто нет такого метода. Возможно, причина в более старой версии jOOQ.

Альтернативный обходной путь — сначала выполнить подзапрос, сохранить его результаты, а затем использовать эти результаты в операторе обновления. В качестве примера:

// First, execute the subquery and fetch the results
Record3<String, Integer, Date> record = dslContext.select(SURVEY_INSTANCE.SURVEY_DEF_ID, SURVEY_INSTANCE.STATUS, SURVEY_INSTANCE.END_DATE)
    .from(SURVEY_INSTANCE)
    .where(SURVEY_INSTANCE.SURVEY_DEF_ID.eq(definitionId))
    .and(SURVEY_INSTANCE.STATUS.notIn(14))
    .orderBy(SURVEY_INSTANCE.END_DATE.desc())
    .limit(1)
    .fetchOne();

// Next, use the results of the subquery in the UPDATE statement
if (record != null) {
    dslContext.update(SURVEY_DEFINITION)
        .set(SURVEY_DEFINITION.LATEST_RESULT, record.get(SURVEY_INSTANCE.STATUS))
        .set(SURVEY_DEFINITION.LATEST_SURVEY_END_DATE, record.get(SURVEY_INSTANCE.END_DATE))
        .where(SURVEY_DEFINITION.ID.eq(record.get(SURVEY_INSTANCE.SURVEY_DEF_ID)))
        .execute();
}

Этот обходной путь разделяет операцию на две части: сначала извлекается запись из подзапроса, а затем используются эти данные для выполнения обновления.

Почему-то не могу сделать джойн после context.update(SD), просто нет такого метода. Возможно, причина в более старой версии jOOQ.

Sebastian Lore 12.06.2023 21:13

@SebastianLore Я отредактировал ответ, чтобы добавить возможный обходной путь.

VonC 12.06.2023 22:08

Спасибо за обходной путь. Я уже сделал это без обходных путей, сильно вдохновленный вашим ответом. Я не мог выполнить соединение после context.update(SD), но я мог сделать context.update(SD.join(...).on(...)), и он генерирует SQL, который очень похож на мой первоначальный SQL.

Sebastian Lore 13.06.2023 14:37

Другие вопросы по теме