如何在同一个表中一次插入可选择包含父行的行

时间:2014-01-30 09:12:25

标签: sql postgresql postgresql-9.2

给出如下表:

CREATE TABLE public.parenttest (
  id      bigserial NOT NULL PRIMARY KEY,
  mydata  varchar(30),
  parent  bigint
  ) WITH (
    OIDS = FALSE
); 

我想插入一堆行。其中一些行应该将之前插入的行的序列生成id作为列parent的值。

例如:

INSERT INTO parenttest (mydata,parent) VALUES ('rootnode',null); 
INSERT INTO parenttest (mydata,parent) VALUES ('child1', /*id of rootnode*/); 
INSERT INTO parenttest (mydata,parent) VALUES ('child2', /*id of rootnode*/); 
INSERT INTO parenttest (mydata,parent) VALUES ('child2.1', /*id of child 2*/);
INSERT INTO parenttest (mydata.parent) VALUES ('child2.2', /*id of child 2*/);

...应该产生以下数据集(id,mydata,parent)

1,'rootnode',null
2,'child1',1
3,'child2',1
4,'child2.1',3
5,'child2.2',3

UNTIL child2.2,当我使用

时,一切都很好
SELECT currval('parenttest_id_seq');

获取父级id,但当然我得到的是child2.2的ID。

对我来说很重要的是,我可以尽可能少地使用客户端请求来完成所有必要的工作 - 我想在服务器端执行所有id生成。

3 个答案:

答案 0 :(得分:1)

如果行可以短暂地拥有NULL父级,那么我就是这样做的。

INSERT INTO parenttest (mydata) VALUES
('rootnode'), 
('child1'),
('child2'), 
('child2.1'),
('child2.2');

UPDATE parenttest SET parent = (select id from parenttest pt where
(pt.mydata = 'rootnode' and parenttest.mydata in ('child1','child2')) or
(pt.mydata = 'child2' and parenttest.mydata in ('child2.1','child2.2')))
WHERE
  mydata in ('child1',
             'child2', 
             'child2.1',
             'child2.2');

fiddle

答案 1 :(得分:1)

你可以做一些丑陋的事情:

INSERT INTO parenttest (mydata,parent) VALUES ('rootnode',null); 
INSERT INTO parenttest (mydata,parent) SELECT 'child1', id FROM parenttest WHERE mydata='rootnode';
INSERT INTO parenttest (mydata,parent) SELECT 'child2', id FROM parenttest WHERE mydata='rootnode';
INSERT INTO parenttest (mydata,parent) SELECT 'child2.1', id FROM parenttest WHERE mydata='child2';
INSERT INTO parenttest (mydata.parent) SELECT 'child2.2', id FROM parenttest WHERE mydata='child2';

我认为在这里做正确的事情是使用客户端,在插入后检索'rootnode'的id,然后在INSERT语句中显式发送以下两个语句及其id。

答案 2 :(得分:0)

经过一些实验,我发现了一个使用匿名PL / PgSQL代码块的解决方案:

DO $$DECLARE
  parentid bigint;
BEGIN  
  INSERT INTO parenttest (mydata) VALUES ('rootnode');  
  parentid:=currval('parenttest_id_seq');  
  INSERT INTO parenttest (mydata,parent) VALUES ('child 1',parentid);
  INSERT INTO parenttest (mydata,parent) VALUES ('child 2',parentid);
  parentid:=currval('parenttest_id_seq');
  INSERT INTO parenttest (mydata,parent) VALUES ('child 2.1',parentid),('child 2.2',parentid);
END$$;

可以在客户端的单个请求中使用它,我不必在客户端生成任何内容,因此这可能是我的问题的一种可能的解决方案。

编辑: 它可以用这样表达:

DO $$DECLARE
  parentid bigint;
BEGIN
  INSERT INTO parenttest (mydata) VALUES ('Flat') RETURNING id INTO parentid;
  INSERT INTO parenttest (mydata, parent) VALUES ('Subflat 1', parentid);
  INSERT INTO parenttest (mydata, parent) VALUES ('Subflat 2', parentid)RETURNING id INTO parentid;
  INSERT INTO parenttest (mydata, parent) VALUES ('Subflat 2.1', parentid), ('Subflat 2.2', parentid);
END$$;