Postgres - вставляет самоссылающуюся упорядоченную запись с помощью оператора INSERT INTO SELECT - PullRequest
0 голосов
/ 05 ноября 2019

Я пытался вставить данные в самоссылающуюся таблицу, в то время как данные были получены из других разных таблиц. Эта строка является своего рода корневой записью и должна иметь собственную ссылку в качестве внешнего ключа. Для облегчения понимания приведем здесь таблицу DDL -

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))

В моем случае мне нужно вставить данные из других таблиц, и, таким образом, оператор будет иметь тип 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_value или currval. Первый запрос работает хорошо даже при использовании с функцией 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

дБ <>скрипка здесь

Ответы [ 2 ]

1 голос
/ 05 ноября 2019

Хотелось бы что-то подобное:

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

0 голосов
/ 05 ноября 2019

Гораздо более распространенный дизайн позволил бы столбцу column_id столбца быть нулевым в случае родительского элемента верхнего уровня. Это также превосходный дизайн;по крайней мере ИМХО. Но

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

Трюк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...