我在复杂模式中有很多表,所有表都按照这样的方式生成:
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
);
不同的表除了nid和修订版之外还有不同的列,它们都有。
这种设计的原因是我们对同一行保持不同的修订(通过非重叠的TSRANGE),但希望不同类型之间的引用在抽象ID之间:s,而不是在特定修订之间(我们在问题时间)。
当我们想要创建新的first
行时,我们首先
INSERT INTO first_id DEFAULT VALUES RETURNING nid
然后我们将此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_id
中插入234个。我们可以使用带有多个CTE的查询:s插入id然后在row_number或类似物上关联,但它变得笨重且难以理解。
相反,我们需要RULE
或TRIGGER
或类似功能,其工作原理如下:
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 ... SELECT ...
,我们也希望它能有效地工作,当然,即使多个事务同时进行,也能正常工作。不幸的是,我还没有足够强大的PostgreSQL力量知道什么是最好的,也不知道它是如何工作的。感谢任何和所有输入。
答案 0 :(得分:2)
您可以在表格中创建触发器,如下所示:
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”计算和“first_id”人口。它将由触发器本身完成。
INSERT INTO first (revisions, column1)
SELECT TSRANGE(NOW()::TIMESTAMP, 'INFINITY'), somecolumn
FROM sometable
WHERE someexpression