如何为没有已知列的 PostgreSQL 视图编写通用更新触发器?
How to write a generic update trigger for PostgreSQL view without known columns?
我正在使用 PostgreSQL 视图来模拟遗留 table,此后已拆分为两个单独的 table,因此我们可以保持与一系列服务的向后兼容性。目标本质上是让这个视图透明地运行,就好像它是拆分之前的原始 table 一样。使用 INSTEAD OF INSERT
触发器,我已经能够很容易地处理插入两个 table 的操作。
但是我正在努力弄清楚如何编写 INSTEAD OF UPDATE
触发器,因为我不知道在任何一个请求中哪些列将被更改(我正在使用 sequelize 所以我不知道确实有任何方法可以控制请求的内容,它可以是 SET
单个列,也可以是所有列)。我在网上找到的所有示例似乎都在更新已知字段(与查询相关的某些元列或知道更新的形状)。
CREATE FUNCTION update_legacy_table_trigger()
RETURNS trigger AS $$
BEGIN
UPDATE table_a SET ??? WHERE id = NEW.id;
UPDATE table_b SET ??? WHERE table_a_id = NEW.id;
END;
$$ LANGUAGE plpgsql;
几个案例:
想象一下:
legacy_table
是视图的名称
table_a
包含以下列:id
、name
、description
、type
、shared_column
和
table_b
包含以下列:id
、table_a_id
(table_a
的外键)、price
、shared_column
.
示例 A:
UPDATE legacy_table SET name="Test", price="10.00" WHERE id="123";
我希望触发器的行为类似于:
UPDATE table_a SET name="Test" WHERE id="123";
UPDATE table_b SET price="10.00" WHERE table_a_id="123";
示例 B: 它也可以只接收一个 table
的更新
UPDATE legacy_table SET price="10.00" WHERE id="123";
所以我们希望触发器的行为类似于:
UPDATE table_b SET price="10.00" WHERE table_a_id="123";
示例 C: 也许一个请求中有很多列
UPDATE legacy_table SET name="Test", price="10.00", description="A test", type="foo", shared_column="bar" WHERE id="123";
所以触发器的行为应该如下:
UPDATE table_a SET name="Test", description="A test", type="foo", shared_column="bar" WHERE id="123";
UPDATE table_b SET price="10.00", shared_column="bar" WHERE table_a_id="123";
可能存在需要对两个 table 进行更新的情况,但我认为在任何情况下原始 UPDATE
中的列名称都不会是任何与新 tables.
中的列名称不同的内容
如果我不明确知道 UPDATE 查询是什么,我将如何编写这个 INSTEAD OF UPDATE
触发器?
您必须为触发器函数中的所有列编写更新语句。您的触发函数如下所示:
CREATE FUNCTION update_legacy_table_trigger()
RETURNS trigger AS $$
BEGIN
UPDATE table_a SET name=new.name, description=new.description,type=new.type, shared_column=new.shared_column WHERE id = NEW.id;
UPDATE table_b SET price=new.price, shared_columns=new.shared_columns WHERE table_a_id = NEW.id;
return null;
END;
$$
LANGUAGE plpgsql;
并且您必须在您的视图中编写触发器,如下所示:
CREATE TRIGGER trg_update_legacy
INSTEAD OF UPDATE
ON legacy_table
FOR EACH ROW
EXECUTE PROCEDURE update_legacy_table_trigger();
这将处理所有更新案例,因为 NEW
将包含更新的行,我们正在使用 NEW
行的数据更新所有字段。
我正在使用 PostgreSQL 视图来模拟遗留 table,此后已拆分为两个单独的 table,因此我们可以保持与一系列服务的向后兼容性。目标本质上是让这个视图透明地运行,就好像它是拆分之前的原始 table 一样。使用 INSTEAD OF INSERT
触发器,我已经能够很容易地处理插入两个 table 的操作。
但是我正在努力弄清楚如何编写 INSTEAD OF UPDATE
触发器,因为我不知道在任何一个请求中哪些列将被更改(我正在使用 sequelize 所以我不知道确实有任何方法可以控制请求的内容,它可以是 SET
单个列,也可以是所有列)。我在网上找到的所有示例似乎都在更新已知字段(与查询相关的某些元列或知道更新的形状)。
CREATE FUNCTION update_legacy_table_trigger()
RETURNS trigger AS $$
BEGIN
UPDATE table_a SET ??? WHERE id = NEW.id;
UPDATE table_b SET ??? WHERE table_a_id = NEW.id;
END;
$$ LANGUAGE plpgsql;
几个案例:
想象一下:
legacy_table
是视图的名称table_a
包含以下列:id
、name
、description
、type
、shared_column
和table_b
包含以下列:id
、table_a_id
(table_a
的外键)、price
、shared_column
.
示例 A:
UPDATE legacy_table SET name="Test", price="10.00" WHERE id="123";
我希望触发器的行为类似于:
UPDATE table_a SET name="Test" WHERE id="123";
UPDATE table_b SET price="10.00" WHERE table_a_id="123";
示例 B: 它也可以只接收一个 table
的更新UPDATE legacy_table SET price="10.00" WHERE id="123";
所以我们希望触发器的行为类似于:
UPDATE table_b SET price="10.00" WHERE table_a_id="123";
示例 C: 也许一个请求中有很多列
UPDATE legacy_table SET name="Test", price="10.00", description="A test", type="foo", shared_column="bar" WHERE id="123";
所以触发器的行为应该如下:
UPDATE table_a SET name="Test", description="A test", type="foo", shared_column="bar" WHERE id="123";
UPDATE table_b SET price="10.00", shared_column="bar" WHERE table_a_id="123";
可能存在需要对两个 table 进行更新的情况,但我认为在任何情况下原始 UPDATE
中的列名称都不会是任何与新 tables.
如果我不明确知道 UPDATE 查询是什么,我将如何编写这个 INSTEAD OF UPDATE
触发器?
您必须为触发器函数中的所有列编写更新语句。您的触发函数如下所示:
CREATE FUNCTION update_legacy_table_trigger()
RETURNS trigger AS $$
BEGIN
UPDATE table_a SET name=new.name, description=new.description,type=new.type, shared_column=new.shared_column WHERE id = NEW.id;
UPDATE table_b SET price=new.price, shared_columns=new.shared_columns WHERE table_a_id = NEW.id;
return null;
END;
$$
LANGUAGE plpgsql;
并且您必须在您的视图中编写触发器,如下所示:
CREATE TRIGGER trg_update_legacy
INSTEAD OF UPDATE
ON legacy_table
FOR EACH ROW
EXECUTE PROCEDURE update_legacy_table_trigger();
这将处理所有更新案例,因为 NEW
将包含更新的行,我们正在使用 NEW
行的数据更新所有字段。