在一个表中插入将自动首先在另一个表中插入(PostgreSQL)

在一个表中插入将自动首先在另一个表中插入(PostgreSQL),postgresql,triggers,Postgresql,Triggers,我在一个复杂的模式中有很多表,所有表都是成对生成的,如下所示: CREATE TABLE first_id ( nid BIGSERIAL PRIMARY KEY ); CREATE TABLE first ( nid BIGINT REFERENCES example_id(nid), revisions TSRANGE NOT NULL, column1 TEXT ); CREATE TABLE second_id ( nid BIGSERIAL

我在一个复杂的模式中有很多表,所有表都是成对生成的,如下所示:

CREATE TABLE first_id (
    nid BIGSERIAL PRIMARY KEY
);

CREATE TABLE first (
    nid BIGINT REFERENCES example_id(nid),
    revisions TSRANGE NOT NULL,
    column1 TEXT
);

CREATE TABLE second_id (
    nid BIGSERIAL PRIMARY KEY
);

CREATE TABLE second (
    nid BIGINT REFERENCES second_id(nid),
    revisions TSRANGE NOT NULL,
    column2 BIGINT REFERENCES first_id(nid),
    column3 TEXT
);
CREATE OR REPLACE FUNCTION f_t_first()
  RETURNS trigger AS
$BODY$
BEGIN
  if (NEW.NID IS NULL) then
    INSERT INTO first_id DEFAULT VALUES RETURNING nid INTO NEW.NID;  
  end if;
  RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;


CREATE TRIGGER t_first
  BEFORE INSERT
  ON first
  FOR EACH ROW
  EXECUTE PROCEDURE f_t_first();
除了nid和修订版,不同的表有不同的列,它们都有

这种设计的原因是我们保持同一行的不同版本(通过非重叠TSRANGE),但希望不同类型之间的引用在抽象ID:s之间,而不是在特定版本之间(我们在提问时解决版本)

当我们想先创建一个新的
行时,我们首先

INSERT INTO first_id DEFAULT VALUES RETURNING nid
然后,我们将该ID提取到调用代码中,并在新查询中再次发出该ID:

INSERT INTO first (nid, revisions, column1) 
  VALUES ([nid from previous query], TSRANGE(NOW()::TIMESTAMP, 'INFINITY'), 'A new string');
当我们一个接一个地创建新ID时,这一切都很好。但我们现在希望从另一个查询批量创建ID,每次数千个。通常我们只是做一些类似的事情

INSERT INTO first (nid, revisions, column1)
  SELECT ???, TSRANGE(NOW()::TIMESTAMP, 'INFINITY'), somecolumn
    FROM sometable
   WHERE someexpression
这当然行不通——如果要插入234行,我们需要在
firstname\u id
中插入234行。我们可以使用一个包含多个CTE:s的查询,这些CTE:s插入ID,然后根据行数或类似的数据进行关联,但它会变得庞大且难以理解

相反,我们需要一个
规则
触发器
或类似的功能,其工作原理如下:

When inserting into first:
  For each new row:
    If <nid> is NULL:
      INSERT INTO first_id, keeping the new <nid>
      Replace the new row's <nid> with the value from the previous step
    Else:
      Keep the new row as is
    Insert the new row into first
插入第一个时:
对于每一新行:
如果为空:
插入第一个_id,保留新的
用上一步中的值替换新行
其他:
保持新行不变
将新行插入第一行

即使我们运行
INSERT。。。选择…
,它会生成数万个新ID,当然,即使在多个事务同时进行的情况下也能正常工作。不幸的是,我对PostgreSQL的力量还不够强大,不知道什么是最好的,也不知道它将如何工作。一如既往地感谢所有的输入。

您可以在表中创建触发器,如下所示:

CREATE TABLE first_id (
    nid BIGSERIAL PRIMARY KEY
);

CREATE TABLE first (
    nid BIGINT REFERENCES example_id(nid),
    revisions TSRANGE NOT NULL,
    column1 TEXT
);

CREATE TABLE second_id (
    nid BIGSERIAL PRIMARY KEY
);

CREATE TABLE second (
    nid BIGINT REFERENCES second_id(nid),
    revisions TSRANGE NOT NULL,
    column2 BIGINT REFERENCES first_id(nid),
    column3 TEXT
);
CREATE OR REPLACE FUNCTION f_t_first()
  RETURNS trigger AS
$BODY$
BEGIN
  if (NEW.NID IS NULL) then
    INSERT INTO first_id DEFAULT VALUES RETURNING nid INTO NEW.NID;  
  end if;
  RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;


CREATE TRIGGER t_first
  BEFORE INSERT
  ON first
  FOR EACH ROW
  EXECUTE PROCEDURE f_t_first();
然后只需插入到“first”表中,而不必担心“nid”计算和“first_id”总体。它将由触发器本身完成

INSERT INTO first (revisions, column1)
  SELECT TSRANGE(NOW()::TIMESTAMP, 'INFINITY'), somecolumn
    FROM sometable
   WHERE someexpression

看看我的答案。