使用相应的值更新表的每一行

时间:2016-12-03 17:24:08

标签: sql database postgresql string-concatenation

我有两个Postgres表:

create table A(
   id_A  serial not null,
   column_A  varchar  null;
   ...);

create table B(
   id_B  serial  not null,
   id_A  int4  not null,
   name  varchar  null,
   keywords  varchar  null,
   ...);

A的元素与表B的多个元素相关联,表B的元素与表A的一个元素相关联。

B中的列关键字是列B.nameA.column_A的值的串联:

B.keywords := B.name || A.column_A

如果更新B.keywords的值,如何使用触发器更新表B中每行的A.column_A列?

换句话说,我想做这样的事情(伪代码):

FOR EACH ROW current_row IN TABLE B
   UPDATE B SET keywords = (SELECT B.name || A.column_A
                            FROM B INNER JOIN A ON B.id_A = A.id_A
                            WHERE B.id_B = current_row.id_B)
   WHERE id_B = current_row.id_B;

2 个答案:

答案 0 :(得分:1)

当A更新时,你的触发器必须调用一个函数:

CREATE OR REPLACE FUNCTION update_b()
  RETURNS TRIGGER
AS $$
BEGIN
  UPDATE B
  SET keywords = name || NEW.column_A
  WHERE id_A = NEW.id_A;
  return NEW;
END
$$ LANGUAGE plpgsql;


CREATE TRIGGER update_b_trigger AFTER UPDATE OF column_A
ON A
FOR EACH ROW
EXECUTE PROCEDURE update_b();

在表B上添加触发器BEFORE INSERT OR UPDATE以设置关键字也可能很有用。

答案 1 :(得分:0)

你的方法被设计破坏了。不要试图在表中保持派生值是最新的。这对于并发访问来说并不安全。可能出现各种并发症。您膨胀表B(和备份)并削弱写入性能。

相反,请使用VIEW(或MATERIALIZED VIEW):

CREATE VIEW ab AS
SELECT B.*, concat_ws(', ', B.name, A.column_A) AS keywords
FROM   B
LEFT   JOIN A USING (id_A);

使用下面的更新表定义,保证了参照完整性,您可以使用[INNER] JOIN代替LEFT [OUTER] JOIN

甚至一个简单的查询就足够了......

无论哪种方式,您需要A中的PRIMARY KEY constraint和表B中的FOREIGN KEY constraint

CREATE TABLE A (
   id_A     serial PRIMARY KEY,
   column_A varchar
   ...);


CREATE TABLE B (
   id_B  serial PRIMARY KEY,
   id_A  int4 NOT NULL REFERENCES A(id_A),
   name  varchar
   --  and *no* redundant "keywords" column!
   ...);

关于串联字符串:

我不会使用CaMeL案例标识符: