我正在将应用程序从 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,因为它现在被读取为纯字符串?
一种可能的解决方案是强制 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();`