【问题标题】:UPSERT: use source column that's not in excluded tableUPSERT:使用不在排除表中的源列
【发布时间】:2019-09-07 09:30:53
【问题描述】:

我正在尝试将 oracle Merge 语句转换为 postgreSQL(>9.5)。 不幸的是,postgres(=MERGE,我发现最好的替代方法是INSERT ... ON CONFLICT,也称为UPSERT

我能够将更基本的合并语句转换为 upsert,但对于更复杂的查询,我需要访问源查询中的列,这些列未插入,但仅用于 DO UPDATE 中的逻辑。 不幸的是,特殊的excluded.-table 使用与目标相同的列标识符。

ORACLE MERGE 版本

MERGE INTO tgt
  USING (SELECT nam.text AS normalizedtext, norm.originaltext,
           norm.entryid AS entryID,
           nam.name_id AS name_id,
           norm.islink AS islink
         FROM norm, nam
         WHERE norm.name_id = nam.name_id
         GROUP BY originaltext
        ) source
  ON (tgt.languagecode = :langCode AND tgt.text = source.originaltext)
  WHEN MATCHED AND ptid IS NULL THEN
    UPDATE SET tgt.name_id = source.name_id,
               tgt.PTID = source.entryID,
               tgt.normname = CASE WHEN source.islink = 1 THEN 
               source.originaltext ELSE source.normalizedtext END CASE

当前 postgress 版本

INSERT INTO tgt (text, normname, ptid, name_id, languagecode)
    SELECT nam.text AS normalizedtext, norm.originaltext,
           norm.entryid AS entryID,
           nam.name_id AS name_id,
           :langCode,           -- edited
           norm.islink AS islink
         FROM norm, nam
         WHERE norm.name_id = nam.name_id
         GROUP BY originaltext
ON CONFLICT (text, languagecode)
DO UPDATE
    SET name_id = excluded.name_id,
           ptid = excluded.ptid,
           normname = CASE WHEN excluded.islink = 1 THEN          -- PROBLEM
           excluded.originaltext ELSE excluded.normalizedtext END -- PROBLEM
    WHERE ptid IS NULL;

问题是排除的表不包含列:isLinkoriginaltextnormalizedtext

错误:列被排除。islink 不存在

是否有任何解决方法或如何在更新查询中使用源列? 如果这不可能,是否有其他替代方法可以在 postgres 中编写合并语句?

【问题讨论】:

  • norm.islink 的值在插入过程中被放入列 languagecode - 开始时看起来是错误的。但如果这确实是正确的,您需要使用目标的表列:CASE WHEN excluded.languagecode = 1 THEN ...
  • 是的,谢谢,我刚刚注意到我忘记了 SELECT 中的 languagecode。但如果没有匹配项,我不希望插入该值。我可以使用一个虚拟列名,也许那没有连接到 tgt 表
  • 现在您的 select 语句包含更多您拥有 INSERT 目标列的列 - 即使没有 ON CONFLICT,这也不起作用。

标签: oracle postgresql merge upsert


【解决方案1】:

您可以将该 CASE 表达式移至 SELECT 语句:

INSERT INTO tgt (text, normname, ptid, name_id, languagecode)
SELECT nam.text, 
       case islink 
         when 1 then norm.originaltext
         else normalizedtext
       end as normname,
       norm.entryid AS ptid,
       nam.name_id AS name_id,
       :langCode as languagecode
FROM norm
  JOIN nam ON norm.name_id = nam.name_id
GROUP BY originaltext
ON CONFLICT (text, languagecode)
DO UPDATE
    SET name_id = excluded.name_id,
           ptid = excluded.ptid,
           normname = excluded.normname
    WHERE ptid IS NULL;

【讨论】:

    猜你喜欢
    • 2018-08-08
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    相关资源
    最近更新 更多