Postgres-使用INSERT INTO SELECT语句插入自引用序列记录

时间:2019-11-05 13:52:35

标签: sql postgresql sequence

我一直在尝试将数据插入自引用表中,而这些数据是从其他不同表中获取的。该行是一个根记录,需要具有自己的引用作为外键。为了便于理解,请在此处提供表DDL-

CREATE TABLE self_refer (
    id        SERIAL  PRIMARY KEY,
    parent_id INTEGER      NOT NULL,
    FOREIGN KEY (parent_id) REFERENCES self_refer(id)
);

如果我们想使用直接值插入数据,则已经讨论了主题here,下面的语句很好用。

INSERT INTO self_refer
            (parent_id)
VALUES      ((SELECT last_value
              FROM   self_refer_id_seq))

就我而言,我需要从其他表中插入数据,因此该语句将为INSERT INTO SELECT类型。以下是我的尝试,它们无法正常工作。

INSERT INTO self_refer
            (parent_id)
SELECT CURRVAL('self_refer_id_seq')

INSERT INTO self_refer
            (parent_id)
SELECT last_value
FROM   self_refer_id_seq 

带有VALUES的第一个语句会适当地插入数据,但是第二个和第三个语句会提取last_valuecurrval的最新数据。即使与currval函数一起使用,第一个查询也能很好地工作。

下面是结果,其中前两个记录显示了通过VALUES插入,而后两个记录则显示了INSERT INTO SELECT语句。

id|parent_id|
--|---------|
47|       47|
48|       48|
49|       48|
50|       49|

寻找有关如何获得前两行之类的结果的帮助,同时使SQL语句与后两行相似。

更新: 接受的答案有效,但可能不是理想的解决方案,请仔细阅读所有有关如何获得更好解决方案的评论。

添加了以下语句,以加快访问速度。如果愿意进行调整,请随时查看db fiddle并尝试其他可能性。

CREATE TABLE self_refer (
    id        SERIAL  PRIMARY KEY,
    parent_id INTEGER      NOT NULL,
    FOREIGN KEY (parent_id) REFERENCES self_refer(id)
);
INSERT INTO self_refer
            (parent_id)
VALUES      ((SELECT last_value
              FROM   self_refer_id_seq))
1 rows affected
INSERT INTO self_refer
            (parent_id)
SELECT CURRVAL('self_refer_id_seq')+1;
1 rows affected
select * from self_refer;
id | parent_id
-: | --------:
 1 |         1
 2 |         2
INSERT INTO self_refer
            (parent_id)
VALUES      ((SELECT last_value
              FROM   self_refer_id_seq))
1 rows affected
select * from self_refer;
id | parent_id
-: | --------:
 1 |         1
 2 |         2
 3 |         3
INSERT INTO self_refer
            (parent_id)
SELECT CURRVAL('self_refer_id_seq')+1;
1 rows affected
select * from self_refer;
id | parent_id
-: | --------:
 1 |         1
 2 |         2
 3 |         3
 4 |         4
INSERT INTO self_refer
            (parent_id)
SELECT last_value +1
FROM   self_refer_id_seq 
1 rows affected
select * from self_refer;
id | parent_id
-: | --------:
 1 |         1
 2 |         2
 3 |         3
 4 |         4
 5 |         5
insert into self_refer values(default, (currval('self_refer_id_seq')));
1 rows affected
select * from self_refer;
id | parent_id
-: | --------:
 1 |         1
 2 |         2
 3 |         3
 4 |         4
 5 |         5
 6 |         6
CREATE FUNCTION my_trigger_function()
RETURNS trigger AS '
BEGIN
  IF NEW.parent_id = -1 THEN
    NEW.parent_id := NEW.id;
  END IF;
  return new;
END ' LANGUAGE 'plpgsql'
create trigger test_t
before insert on self_refer
for each row
EXECUTE PROCEDURE my_trigger_function()
INSERT INTO self_refer
            (parent_id)
SELECT -1
1 rows affected
select * from self_refer;
id | parent_id
-: | --------:
 1 |         1
 2 |         2
 3 |         3
 4 |         4
 5 |         5
 6 |         6
 7 |         7
INSERT INTO self_refer
            (parent_id)
SELECT 5
1 rows affected
select * from self_refer;
id | parent_id
-: | --------:
 1 |         1
 2 |         2
 3 |         3
 4 |         4
 5 |         5
 6 |         6
 7 |         7
 8 |         5

db <>提琴here

2 个答案:

答案 0 :(得分:1)

这样的选择是否可以解决:

INSERT INTO self_refer
            (parent_id)
SELECT CURRVAL('self_refer_id_seq')+1;

INSERT INTO self_refer
            (parent_id)
SELECT last_value +1
FROM   self_refer_id_seq 

它确实有效:DEMO

答案 1 :(得分:0)

更常见的设计是,在顶级父级的情况下,列column parent_id可以为null。这也是一个出色的设计;至少恕我直言。但是

insert into self_refer values(default, (currval('self_refer_id_seq')));

做到了。