【问题标题】:How to duplicate and modify table rows using Jooq insertInto如何使用 Jooq insertInto 复制和修改表行
【发布时间】:2018-05-25 05:35:00
【问题描述】:

我正在使用 Jooq,并试图在同一个表中生成数据集的近似副本。在此过程中,我想将一个字段的值更新为已知值。我一直在查看文档并尝试变体,但还没有运气。这是我更新 REGISTRATION 表并将“阶段”字段设置为值 6(它是 5)的方法。所以我最终会得到原始数据加上一个只有不同阶段值的重复集。 在伪代码中

insert into Registration (select * from Registration where stage=5) set stage=6 

我在下面尝试了这段代码,并认为我可以添加一个“.set(...)”方法来设置值,但这似乎无效。

create.insertInto(REGISTRATION)
    .select(
        (selectFrom(REGISTRATION)
            .where(REGISTRATION.STAGE.eq(5))
        )
    ).execute();

【问题讨论】:

  • 有趣的语法。哪个数据库支持在INSERT .. SELECT 之后附加SET 子句?

标签: java sql duplicates rows jooq


【解决方案1】:

我不知道支持INSERT .. SELECT .. SET 语法的数据库,如果有这样的语法,它肯定不符合SQL 标准。这里的前进方式是这样写:

在 SQL 中:

INSERT INTO registration (col1, col2, col3, stage, col4, col5)
SELECT col1, col2, col3, 6, col4, col5
FROM registration
WHERE stage = 5;

在 jOOQ 中:

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();

隐含以下静态导入:

import static org.jooq.impl.DSL.*;

在 jOOQ 中,动态

由于您正在寻找动态 SQL 解决方案,因此可以这样做:

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();
}

【讨论】:

  • 谢谢,但我试图避免这种显式的逐列方法,因为我想在多个表中应用它。所有这些中唯一的共同列将是这个“阶段”列,它将被设置为相同的值。我想知道是否有面向字段列表的方法?
  • 这是面向字段列表的方法。您可以将数组或集合传递给所有这些方法并动态组合它们。永远记住,每个 jOOQ 查询都是动态 SQL 查询:jooq.org/doc/latest/manual/sql-building/dynamic-sql
  • 有趣的链接,没有意识到 jOOQ 可以做到这一点。我得到的概念是,我应该将 select 语句传递给每个表中的字段列表。最里面的选择应该传递相同的列表,但替换为“阶段”值。我认为正确的语法可能有点挑战 - 需要更多阅读!
  • @wholeroll:完全没问题。我已经用动态版本更新了我的答案以说明您的情况...
【解决方案2】:

感谢 Lukas 的回答,我将使用它的一个版本,因为它既好又通用。我刚刚开始工作的我自己的答案不太笼统,但对于其他人来说可能是一个有用的参考,特别是因为它考虑了身份字段“id”,否则可能会导致问题。

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();
    }

【讨论】:

  • 感谢您记录此内容。并祝贺 Stack Overflow 上的 jOOQ 问题 #1000! :)
猜你喜欢
  • 1970-01-01
  • 2022-01-09
  • 2013-10-24
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多