复制行和外键行,保持关系/顺序

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

我有两个具有 1:1 关系的表(PostgreSQL 12):

CREATE TABLE public.objects (
    id uuid DEFAULT public.gen_random_uuid () NOT NULL PRIMARY KEY UNIQUE,
    name text NOT NULL,
    object_type_a_id uuid NOT NULL
);

CREATE TABLE public.object_type_a (
    id uuid DEFAULT public.gen_random_uuid () NOT NULL PRIMARY KEY UNIQUE,
    description text NOT NULL
);

ALTER TABLE ONLY public.objects
    ADD CONSTRAINT objects_object_type_a_id_fkey FOREIGN KEY (object_type_a_id) REFERENCES public.object_type_a (id) ON UPDATE RESTRICT ON DELETE RESTRICT;

INSERT INTO public.object_type_a (description) VALUES ('desc_1'), ('desc_2'), ('desc_3');
INSERT INTO objects (name, object_type_a_id) SELECT 'name_1', id FROM object_type_a WHERE description = 'desc_1';
INSERT INTO objects (name, object_type_a_id) SELECT 'name_2', id FROM object_type_a WHERE description = 'desc_2';
INSERT INTO objects (name, object_type_a_id) SELECT 'name_3', id FROM object_type_a WHERE description = 'desc_3';

我现在必须复制

objects
object_type_a
中的所有行,保留关系以及
objects.name
object_type_a.description
中的所有值,因此它看起来像这样:

objects
---------------------------------
id    | name   | object_type_a_id
---------------------------------
847c..| name_1 | 5b7d..
ae3e..| name_2 | 4ce4..
41fd..| name_3 | bffa..
d570..| name_1 | eeec..
4cfd..| name_2 | 4bb0..
892f..| name_3 | aeff..

object_type_a
--------------------
id    | description 
--------------------
5b7d..| desc_1
4ce4..| desc_2
bffa..| desc_3
eeec..| desc_1
4bb0..| desc_2
aeff..| desc_3

我尝试使用 CTE/子查询,从

objects
object_type_a
中选择所有行,然后插入/更新
objects
,但这显然会混淆关系,并且一次执行一行似乎是效率相当低。

sql postgresql foreign-keys
2个回答
0
投票

假设

description
在“a”表中是唯一的,那么你可以采取以下方法:

  • 将新的“a”对象插入到“a”表中。
  • 查找现有的“a”对象,然后根据
    description
    匹配新插入的对象。
  • 将此匹配用于插入行。

Postgres 允许使用 DML 语句进行 CTE,返回已更改行的值,因此这一切都可以在一条语句中完成:

with oa as (
      insert into objects_type_a (description)
          select description
          from object_type_a oa
          where exists (select 1 from objects o where oa.id = o.object_type_a_id)
          returning *
     )
insert into objects (name, object_type_a_id)
    select o.name, oa.id
    from objects o join
         object_type_a oa_orig
         on o.object_type_a_id = oa_orig.id join
         oa
         on oa_orig.description = oa.description;

这里是一个db<>小提琴。


0
投票

如果描述不唯一,那么我认为这是可行的。 它在 CTE 中生成新的 object_type_a.id,允许您在插入对象表时将旧 id 映射到新 id:

with oa_copies as (
  select
    id,
    gen_random_uuid() as new_id,
    description
    FROM object_type_a oa
   where exists (select 1 from objects o where oa.id = o.object_type_a_id)
),

  x as (
    insert into object_type_a (id, description)
    select
      new_id,
      description
      from oa_copies
  )

insert into objects (name, object_type_a_id)
select    
  o.name,
  oac.new_id
  from objects o
       join oa_copies oac on oac.id = o.object_type_a_id;
© www.soinside.com 2019 - 2024. All rights reserved.