UPSERT:使用不在排除表中的源列

时间:2019-04-17 07:44:47

标签: oracle postgresql merge upsert

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

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

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

当前发布版本

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中编写merge语句?

1 个答案:

答案 0 :(得分:0)

您可以将该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;