I'm using Jooq and am trying to generate a near copy of a data set within the same table. In the process I want to update the value of one field to a known value. I've been looking at the docs & trying variations with no luck yet. Here is my approach updating the REGISTRATION table and setting the 'stage' field to the value 6 (where it was 5). So I'll end up with the original data plus a duplicate set with just the different stage value. in pseudo code
insert into Registration (select * from Registration where stage=5) set stage=6
I tried this code below and thinking I could add a ".set(...)" method to set the value but that doesn't seem to be valid.
create.insertInto(REGISTRATION)
.select(
(selectFrom(REGISTRATION)
.where(REGISTRATION.STAGE.eq(5))
)
).execute();
I'm not aware of a database that supports an INSERT .. SELECT .. SET
syntax, and if there were such a syntax, it certainly isn't SQL standards compliant. The way forward here would be to write:
INSERT INTO registration (col1, col2, col3, stage, col4, col5)
SELECT col1, col2, col3, 6, col4, col5
FROM registration
WHERE stage = 5;
create.insertInto(REGISTRATION)
.columns(
REGISTRATION.COL1,
REGISTRATION.COL2,
REGISTRATION.COL3,
REGISTRATION.STAGE,
REGISTRATION.COL4,
REGISTRATION.COL5)
.select(
select(
REGISTRATION.COL1,
REGISTRATION.COL2,
REGISTRATION.COL3,
val(6),
REGISTRATION.COL4,
REGISTRATION.COL5)
.from(REGISTRATION)
.where(REGISTRATION.STAGE.eq(5)))
.execute();
The following static import is implied:
import static org.jooq.impl.DSL.*;
Since you're looking for a dynamic SQL solution, here's how this could be done:
static <T> int copy(
DSLContext create, Table<?> table, Field<T> field,
T oldValue, T newValue
) {
List<Field<?>> into = new ArrayList<>();
List<Field<?>> from = new ArrayList<>();
into.addAll(Stream.of(table.fields())
.filter(f -> !field.equals(f))
.collect(toList()));
from.addAll(into);
into.add(field);
from.add(val(newValue));
return
create.insertInto(table)
.columns(into)
.select(
select(from)
.from(table)
.where(field.eq(oldValue))
.execute();
}
Thanks Lukas for your answer which I'll use a version of as it's nice and general. My own answer which I just got to work is less general but might be a useful reference for other people who come this way especially as it takes account of the identity field "id" which can otherwise cause problems.
public void duplicate(int baseStage, int newStage) {
Field<?>[] allFieldsExceptId = Stream.of(REGISTRATION.fields())
.filter(field -> !field.getName().equals("id"))
.toArray(Field[]::new);
Field<?>[] newFields = Stream.of(allFieldsExceptId).map(field -> {
if (field.getName().contentEquals("stage")) {
return val(newStage);
} else {
return field;
}
}).toArray(Field[]::new);
create.insertInto(REGISTRATION)
.columns(allFieldsExceptId)
.select(
select(newFields)
.from(REGISTRATION)
.where(REGISTRATION.STAGE.eq(baseStage)))
.execute();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With