Home > Blockchain >  Subquery inside an update to set multiple values
Subquery inside an update to set multiple values

Time:09-25

I want to move a DateTime of a record by using update().set(). When I try the given example in the jOOQ docs for using a subselect I found that I needed to cast to a Row2 type because I want to set two variables. With this, the query gets build in an unusual way (or at least not according to what I expect of the query given the example in the jOOQ docs):

public static void moveEventStart(final LocalDate previousEventStart, final LocalDate newEventStart) {
    final Days changeInterval = Days.daysBetween(previousEventStart, newEventStart);
    ActivityTbl a = ACTIVITY.as("a");
    ActivityTbl a2 = ACTIVITY.as("a2")

    jooq()
        .update(a)
        .set(
            (Row2) row(a.START, a.END),
            select(
                 models.Jooq.dateAdd(a2.START, changeInterval.getDays(), DatePart.DAY),
                 models.Jooq.dateAdd(a2.END, changeInterval.getDays(), DatePart.DAY))
            .from(a2)
            .where(...))
        .where(...)
        .execute();
}

The dateAdd function is build like this:

public static Field<Date> dateAdd(TableField<?, LocalDateTime> field, int interval, DatePart datePart) {
    String unit;
    switch (datePart) {
      case YEAR:
        unit = "YEAR";
        break;
      case MONTH:
        unit = "MONTH";
        break;
      case DAY:
        unit = "DAY";
        break;
      case HOUR:
        unit = "HOUR";
        break;
      case MINUTE:
        unit = "MINUTE";
        break;
      case SECOND:
        unit = "SECOND";
        break;
      default:
        unit = "";
    }
    return DSL.field(
        "DATE_ADD({0}, INTERVAL {1} "   unit   ")", SQLDataType.DATE, field, DSL.inline(interval));
  }

Produces:

update `Activity` as `a` 
set(`start`, `end`) = (
    select * from (
        select 
            DATE_ADD(`a2`.`start`, INTERVAL 1 DAY), 
            DATE_ADD(`a2`.`end`, INTERVAL 1 DAY) 
        from `Activity` as `a2` 
        where (...) as `t`
    ) 
where (...)

Why does jOOQ build a select on top of the already given select? And how do I make this work, so it sets the multiple values according to the given select?

CodePudding user response:

The syntax isn't supported by MySQL

MySQL doesn't support this syntax yet. You can see that on the Javadoc of jOOQ's UpdateSetFirstStep.set(Row2, Select) method, which lists these dialects as supported:

@Support({ASE,AURORA_POSTGRES,BIGQUERY,COCKROACHDB,DB2,H2,HANA,HSQLDB,INGRES,ORACLE,POSTGRES,SNOWFLAKE,SQLSERVER,SYBASE})

jOOQ could emulate the syntax:

Both of these emulations aren't available yet as of jOOQ 3.15

If the syntax was supported, why the extra derived table?

If the syntax was supported, then the additional derived table is a workaround implemented by jOOQ for a limitation in MySQL, where an UPDATE or DELETE query cannot reference the DML statement's target table from within a correlated subquery (but magically, this limitations disappears when nesting the correlated subquery one level in a derived table). See:

  • Related