jooq 在 postgres 上生成无效的合并更新插入

问题描述 投票:0回答:1

我正在将应用程序从 postgres 12 和 jooq 3.15.4(专业)迁移到 postgres 16 和 jooq 3.18.7(专业)。我有一些使用“onDuplicateKeyUpdate()”的查询导致迁移问题,因为 jooq 现在生成一个不在 postgres 上执行的“合并到”查询。在迁移之前,它生成了一个有效的“插入..冲突..执行更新..”。我想知道这是怎么回事。 postgres 是否完全支持“合并到”语法?

因为我需要问这个问题,所以我创建了一个我的问题的模拟示例。具有讽刺意味的是,这个模拟示例生成了“在冲突时插入 ..”查询,该查询有效。

        return DSL
            .insertInto(
                fruitTable,
                fruitTable.FRUIT_ID,
                fruitTable.NAME,
            )
            .values(
                mandate.mandateId,
                "Banana",
            )
            .onDuplicateKeyUpdate()
            .set(fruitTable.NAME, "Apple")

结果:

insert into "public"."fruit" as "fr" ("fruit_id", "name") values ('2f8a4b65-7e1e-49d4-8530-ae2b6bb08857', 'Banana') on conflict ("fruit_id") do update set "name" = 'Apple';

-- is OK!

但是我原来的示例导致“合并到”,别名有问题,

    return DSL
            .insertInto(
                mandateTable,
                mandateTable.MANDATE_ID,
                mandateTable.LAST_UPDATE,
                )
            .values(
                mandate.mandateId,
                LocalDateTime.now(zid),
            )
        .onDuplicateKeyUpdate()
        .set(mandateTable.LAST_UPDATE, LocalDateTime.now(zid))
-- Executing SQL:

merge into "public"."mandate" as "m" using (select '2f8a4b65-7e1e-49d4-8530-ae2b6bb08857', timestamp '2023-12-07 18:05:33.033756553') as "t" ("mandate_id", "last_update") on ("public"."mandate"."mandate_id" = "t"."mandate_id" or "public"."mandate"."portfolio_id" = null) when matched then update set "last_update" = timestamp '2023-12-07 18:05:33.033877463' when not matched then insert ("mandate_id", "last_update") values ("t"."mandate_id", "t"."last_update");

-- org.jooq.exception.DataAccessException:
-- SQL [merge into "public"."mandate" as "m" using (select '2f8a4b65-7e1e-49d4-8530-ae2b6bb08857', timestamp '2023-12-07 18:05:33.033756553') as "t" ("mandate_id", "last_update") on ("public"."mandate"."mandate_id" = "t"."mandate_id" or "public"."mandate"."portfolio_id" = null) when matched then update set "last_update" = timestamp '2023-12-07 18:05:33.033877463' when not matched then insert ("mandate_id", "last_update") values ("t"."mandate_id", "t"."last_update")]; Batch entry 1 merge into "public"."mandate" as "m" using (select '2f8a4b65-7e1e-49d4-8530-ae2b6bb08857', timestamp '2023-12-07 18:05:33.033756553') as "t" ("mandate_id", "last_update") on ("public"."mandate"."mandate_id" = "t"."mandate_id" or "public"."mandate"."portfolio_id" = null) when matched then update set "last_update" = timestamp '2023-12-07 18:05:33.033877463' when not matched then insert ("mandate_id", "last_update") values ("t"."mandate_id", "t"."last_update")
-- was aborted: ERROR: invalid reference to FROM-clause entry for table "mandate"
--  Hint: Perhaps you meant to reference the table alias "m".

如果我删除别名,我就会遇到下一个问题,

    return DSL
            .insertInto(
                Tables.MANDATE,
                Tables.MANDATE.MANDATE_ID,
                Tables.MANDATE.LAST_UPDATE,
                )
            .values(
                Tables.MANDATE.mandateId,
                LocalDateTime.now(zid),
            )
        .onDuplicateKeyUpdate()
        .set(Tables.MANDATE.LAST_UPDATE, LocalDateTime.now(zid))
-- Executing SQL:

merge into "public"."mandate" using (select '39d98a7c-39f2-4898-840d-90df7b22884b', timestamp '2023-12-07 17:57:27.106425382') as "t" ("mandate_id", "last_update") on ("public"."mandate"."mandate_id" = "t"."mandate_id" or "public"."mandate"."portfolio_id" = null) when matched then update set "last_update" = timestamp '2023-12-07 17:57:27.106553633' when not matched then insert ("mandate_id", "last_update") values ("t"."mandate_id", "t"."last_update");

-- Result: org.jooq.exception.DataAccessException:
-- SQL [merge into "public"."mandate" using (select '39d98a7c-39f2-4898-840d-90df7b22884b', timestamp '2023-12-07 17:57:27.106425382') as "t" ("mandate_id", "last_update") on ("public"."mandate"."mandate_id" = "t"."mandate_id" or "public"."mandate"."portfolio_id" = null) when matched then update set "last_update" = timestamp '2023-12-07 17:57:27.106553633' when not matched then insert ("mandate_id", "last_update") values ("t"."mandate_id", "t"."last_update")]; Batch entry 1 merge into "public"."mandate" using (select '39d98a7c-39f2-4898-840d-90df7b22884b', timestamp '2023-12-07 17:57:27.106425382') as "t" ("mandate_id", "last_update") on ("public"."mandate"."mandate_id" = "t"."mandate_id" or "public"."mandate"."portfolio_id" = null) when matched then update set "last_update" = timestamp '2023-12-07 17:57:27.106553633' when not matched then insert ("mandate_id", "last_update") values ("t"."mandate_id", "t"."last_update")
-- was aborted: ERROR: operator does not exist: uuid = text
--   Hint: No operator matches the given name and argument types. You might need to add explicit type casts.

我认为该解决方案需要强制生成“插入”来代替合并。或者确保 id 字段被数据库读取为 uuid,因为它现在被读取为纯字符串?

postgresql jooq
1个回答
0
投票

一种可能的解决方案是强制 JOOQ 生成 insert into ... onconflict ... do update ... 语法,而不是 merge into 语法。这可以通过使用 onConflictDoUpdate() 方法而不是像这样的 onDuplicateKeyUpdate() 方法来实现

return DSL
    .insertInto(mandateTable, mandateTable.MANDATE_ID, mandateTable.LAST_UPDATE)
    .values(mandate.mandateId, LocalDateTime.now(zid))
    .onConflict(mandateTable.MANDATE_ID)
    .doUpdate()
    .set(mandateTable.LAST_UPDATE, LocalDateTime.now(zid))
    .execute();`

© www.soinside.com 2019 - 2024. All rights reserved.