Как добиться вложенного оператора INSERT в PostgreSQL? - PullRequest
1 голос
/ 18 марта 2019

У меня есть две таблицы, group и groupmembers. При вставке строки в таблицу group я также хочу вставить в таблицу groupmembers два значения: groupid (идентификатор из таблицы групп) и userid (идентификатор пользователя, создавшего группу). Это таблицы:

CREATE TABLE <b>groups</b> (
  id SERIAL PRIMARY KEY NOT NULL,
  name CHARACTER VARYING(255) NOT NULL,
  creator CHARACTER VARYING(255) NOT NULL,
  role CHARACTER VARYING(100) NOT NULL DEFAULT ('admin'),
  createdon TIMESTAMP WITH TIME ZONE DEFAULT now(),
  FOREIGN KEY (creator) references users (email) on delete CASCADE
);

CREATE TABLE <b>groupmembers</b> (
  id SERIAL PRIMARY KEY NOT NULL,
  groupid INTEGER NOT NULL,
  userid INTEGER NOT NULL,
  createdon TIMESTAMP WITH TIME ZONE DEFAULT now(),
  FOREIGN KEY (groupid) references groups (id) on delete CASCADE,
  FOREIGN KEY (userid) references users (id) on delete CASCADE
);

 CREATE TABLE <b>users</b> (
    id SERIAL PRIMARY KEY NOT NULL,
    firstname CHARACTER VARYING(255) NOT NULL,
    lastname CHARACTER VARYING(255) NOT NULL,
    email CHARACTER VARYING(50) UNIQUE NOT NULL,
    password CHARACTER VARYING(255) NOT NULL,
    registeredon TIMESTAMP WITH TIME ZONE DEFAULT now()
  );

Оператор вставки в таблицу групп:

INSERT INTO groups (name, creator) VALUES ($1, $2) RETURNING *;

Как добавить еще один оператор вставки, который вставляет значения в столбцы groupid и userid таблицы groupmembers?

Я видел это, но, похоже, он не отвечает на мой вопрос:
Вложенные в PostgreSQL INSERT / WITH для вставки внешнего ключа

1 Ответ

1 голос
/ 18 марта 2019

Я предлагаю обернуть обе вставки в один запрос с помощью CTE, модифицирующего данные * , например:

WITH grp_ins AS (
   INSERT INTO groups (name, creator)
   VALUES ($1, $2)
   RETURNING id, creator
   )
INSERT INTO groupmembers (groupid, userid)
SELECT g.id, u.id 
FROM   grp_ins    g
JOIN   users u ON u.email = g.creator;

Так как groups.creator определено NOT NULL с ограничением FK, обеспечивающим ссылочную целостность, [INNER] JOIN - это хорошо.Иначе я бы рассмотрел LEFT JOIN.

Так же, как ответ, на который вы ссылались .Или эти:

Если по какой-то причине вы не можете применить приведенную выше команду (например, вложенную в функцию, которая должна использоваться для вставки в groups), следующая лучшая вещь - это Триггер AFTER INSERT для выполнения второго INSERT.Немного сложнее и дороже.Но выполняет работу:

CREATE OR REPLACE FUNCTION trg_ins_row_in_groupmembers()
  RETURNS trigger AS
$func$
BEGIN
   INSERT INTO groupmembers (groupid, userid)
   SELECT NEW.id, (SELECT u.id FROM users u WHERE u.email = NEW.creator);

   RETURN NEW;  -- doesn't matter much what you return here
END
$func$  LANGUAGE plpgsql;

И триггер AFTER INSERT на groups:

CREATE TRIGGER groups_ins_aft
AFTER INSERT ON groups
FOR EACH ROW EXECUTE PROCEDURE trg_ins_row_in_groupmembers();

Связано:

...