У меня есть следующее (немного сложное для меня) обновление 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 У меня есть. Но я не понимаю, как это использовать.
Я имею в виду, что на скриншоте очевидная ошибка, но, может быть, у вас есть более конкретные вопросы?




Конкретная проблема на вашем снимке экрана заключается в том, что вы неправильно разместили закрывающую скобку:
.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, поэтому долго изучал его). Проголосовал.
Предоставленный вами 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.
@SebastianLore Я отредактировал ответ, чтобы добавить возможный обходной путь.
Спасибо за обходной путь. Я уже сделал это без обходных путей, сильно вдохновленный вашим ответом. Я не мог выполнить соединение после context.update(SD), но я мог сделать context.update(SD.join(...).on(...)), и он генерирует SQL, который очень похож на мой первоначальный SQL.
Вы ознакомились со страницей руководства по созданию производных таблиц?