具有主键冲突的子记录的批量移动(子记录的合并)

时间:2016-02-11 20:37:10

标签: database postgresql

在PostgreSQL 9.5中,我有一个表:A

表A有两个属性:

  1. recid - 表的主键(序列号)
  2. description - 表(文本)的唯一键
  3. 表A的主键被其他表用作外键,其定义为:

    CONSTRAINT fk FOREIGN KEY (A_recid)
          REFERENCES A (recid) MATCH SIMPLE
          ON UPDATE CASCADE ON DELETE RESTRICT
    

    我需要将表A中记录1中的描述更改为记录2中已存在的描述,并删除记录1以保持表的唯一描述。

    表A中的记录1将在其他表中具有子记录,这些子记录需要根据外键约束的级联更新移动到记录2的新recid。

    这是怎么做到的?是否可以使用可写的CTE?

    (如有必要,我不反对改变表格设计)。

    非常感谢任何建议。

    编辑#1父表的完整表声明是:

    CREATE TABLE cpt
    (
      recid serial NOT NULL,
      code text,
      cdesc text NOT NULL,
      modified timestamp without time zone DEFAULT now(),
      procedure_type text,
      CONSTRAINT pk_cpt_recid PRIMARY KEY (recid),
      CONSTRAINT cpt_noduplicate UNIQUE (cdesc)
    )
    WITH (
      OIDS=FALSE
    );
    ALTER TABLE cpt
      OWNER TO postgres;
    

    子表的示例(许多表中的一个):

    CREATE TABLE cpt_invoice
    (
      recid serial NOT NULL,
      cpt_recid integer NOT NULL,
      ninsurance numeric(10,2),
      ncash numeric(10,2),
      mustschedule boolean,
      doneinoffice boolean,
      common boolean,
      "timestamp" timestamp without time zone DEFAULT now(),
      modified timestamp without time zone DEFAULT now(),
      CONSTRAINT pk_cpt_invoice_recid PRIMARY KEY (recid),
      CONSTRAINT cs_cpt_invoice FOREIGN KEY (cpt_recid)
          REFERENCES cpt (recid) MATCH SIMPLE
          ON UPDATE CASCADE ON DELETE CASCADE,
      CONSTRAINT cs_unique_cpt_invoice UNIQUE (cpt_recid)
    )
    WITH (
      OIDS=FALSE
    );
    ALTER TABLE cpt_invoice
      OWNER TO postgres;
    

    编辑#2:这是我所希望的。但这不适用于错误:

    错误:更新或删除表格" cpt"违反外键约束" nursebilling_cpt_fk"在桌子上"护士"详细信息:Key(recid)=(459)仍然从表格#34; carebilling"中引用。

    with plana as (  -- get snapshot of original record
        select * from cpt where recid = 459
    )
    , planb as (  -- change the primary key on snapshot -- I am hoping this will be cascaded
        update cpt
        set recid = 2
        from plana
        where cpt.recid = plana.recid
    )   
    , planc as ( -- delete the one-to-one record in cpt_invoice
        delete from cpt_invoice
        using planA 
        where cpt_invoice.cpt_recid = planA.recid
    )
    , pland as(  -- delete the now unused record from cpt
        delete from cpt
        using plana
        where plana.cdesc = cpt.cdesc
    )
    select * from cpt
    

1 个答案:

答案 0 :(得分:0)

嗯,经过进一步调查后,Erwin Brandstetter

披露了问题的关键
  

如果您需要任何FOREIGN KEY约束来引用列,   DEFERRABLE不是一个选项,因为(根据文档):

     

引用的列必须是不可延迟的唯一列   或引用表中的主键约束。

因此,CTE已经出局了,我留下了一个plpgsql脚本,它在某种程度上必须显式查找子表,移动子记录,然后删除旧的父记录。