PostgreSQL:在不同表的多个列中的某些列上进行条件插入

PostgreSQL: Conditional INSERT INTO on some of multiple columns from difference tables

拜托,我是 PostgreSQL/PLPGSQL 的新手,我曾尝试在 Google 上到处搜索 SO,但找不到具体的解决方案。如果重复这个问题,我深表歉意。

我想创建可以从 table_main 插入值的触发器函数,如果其他子 table 有值,自定义字符串 (link) 将是插入到与来自 table_main 的数据一致的同一行中。

我有 3 个 table 由应用程序自动生成,类似于:

-- table_main

CREATE TABLE table_main
(
  main_a character varying(80) NOT NULL,
  main_b character varying(255),
  main_c character varying(255),
  main_d character varying(255),
  CONSTRAINT main_a_pkey UNIQUE (main_a)
);

-- table_sub1

CREATE TABLE table_sub1
(
  sub_a character varying(80) NOT NULL,
  sub_b character varying(255),
  sub_c character varying(255),
  sub_d character varying(255),
  CONSTRAINT table_sub1_pkey UNIQUE (sub_a)
);

-- table_sub2

CREATE TABLE table_sub2
(
  sub2_a character varying(80) NOT NULL,
  sub2_b character varying(255),
  sub2_c character varying(255),
  sub2_d character varying(255),
  CONSTRAINT table_sub2_pkey UNIQUE (sub2_a)
);

此外,我还有另一个table来存储要从table_main和自定义字符串(links)复制的数据,如下所示:

-- table_copy

CREATE TABLE table_copy
(
  id serial NOT NULL,
  copy_a character varying(80),
  copy_b character varying(255),
  copy_c character varying(255),
  copy_d character varying(255),
  copy_e character varying(255),
  copy_f character varying(255),
  copy_g character varying(255)
);

我的目的是:

  1. 将数据从 table_main 复制到 table_copy,当一条记录插入 table_main 时,使用下面的触发函数,它工作正常:

.

CREATE OR REPLACE FUNCTION save_data()
RETURNS trigger
AS $$
BEGIN
INSERT INTO table_copy (
copy_a,
copy_b,
copy_c,
copy_d)
VALUES ( 
NEW."main_a", 
NEW."main_b",
NEW."main_c",
NEW."main_d"
);
RETURN NEW;
END $$ LANGUAGE plpgsql;
ALTER FUNCTION save_data() OWNER TO postgres;
DROP TRIGGER trigger_save_data ON "table_main";
CREATE TRIGGER trigger_save_data BEFORE INSERT OR UPDATE 
ON "table_main" FOR EACH ROW EXECUTE PROCEDURE save_data();

检查和结果:

smart=# INSERT INTO table_main (main_a, main_b, main_c, main_d) VALUES ('aaa', 'bbb', 'ccc', 'ddd');
INSERT 0 1
smart=# SELECT * FROM table_copy;
 id | copy_a | copy_b | copy_c | copy_d | copy_e | copy_f | copy_g
----+--------+--------+--------+--------+--------+--------+--------
  3 | aaa    | bbb    | ccc    | ddd    |        |        |
(1 row)
  1. 我的第二个(也是更重要的)目的是根据 table_sub1 和 [=21] 的条件将自定义字符串插入 table_copy 的最后几列(当然是在同一行) =],例如,IF table_sub1.sub_ctable_sub2.sub2_d 已插入值,自定义字符串 (links) 将分别插入 table_copy.copy_etable_copy.copy_f

我尝试了下面的一些解决方案,但都不让我满意。

解决方案 1:在 table_maintable_sub1table_sub2 中的每个 table 上设置每个触发器。结果:它在 table_copy ==> not accepted.

中创建了三行

触发于 table_sub1:

CREATE OR REPLACE FUNCTION save_data_sub1()
RETURNS trigger
AS $$
BEGIN
INSERT INTO table_copy (copy_e) VALUES ('link_to_sub1_here');
RETURN NEW;
END $$ LANGUAGE plpgsql;
ALTER FUNCTION save_data_sub1() OWNER TO postgres;
CREATE TRIGGER trigger_save_data_sub1 BEFORE INSERT OR UPDATE 
ON "table_sub1" FOR EACH ROW EXECUTE PROCEDURE save_data_sub1();

触发于 table_sub2:

CREATE OR REPLACE FUNCTION save_data_sub2()
RETURNS trigger
AS $$
BEGIN
INSERT INTO table_copy (copy_f) VALUES ('link_to_sub2_here');
RETURN NEW;
END $$ LANGUAGE plpgsql;
ALTER FUNCTION save_data_sub2() OWNER TO postgres;
CREATE TRIGGER trigger_save_data_sub1 BEFORE INSERT OR UPDATE 
ON "table_sub2" FOR EACH ROW EXECUTE PROCEDURE save_data_sub2();

测试和结果(上面所有 3 个触发器):

smart=# INSERT INTO table_sub1 VALUES ('abc', 'bca', 'aaa', 'cba');
INSERT 0 1
smart=# INSERT INTO table_sub2 VALUES ('cvb', 'bvc', 'aaa', 'vcb');
INSERT 0 1
smart=# SELECT * FROM table_copy;
 id | copy_a | copy_b | copy_c | copy_d |      copy_e       |      copy_f       | copy_g
----+--------+--------+--------+--------+-------------------+-------------------+--------
  6 | aaa    | bbb    | ccc    | ddd    |                   |                   |
  7 |        |        |        |        | link_to_sub1_here |                   |
  8 |        |        |        |        |                   | link_to_sub2_here |
(3 rows)


smart=#

解决方案 2:在上面的触发函数 save_data() 中使用 RETURN NEW; 正下方的 IF EXISTS (SELECT........ WHERE) THEN INSERT INTO table_copy (copy_e) VALUES ('a link here') END IF;,它仍然会生成新行。 ==> 也不接受。

解决方案 3:使用相同的 IF EXISTS ...... THEN .... 以上,==> ERROR。

我想要的是,数据插入一行(6),而不是生成三行。这是我的期望:

 id | copy_a | copy_b | copy_c | copy_d |      copy_e       |      copy_f       | copy_g
----+--------+--------+--------+--------+-------------------+-------------------+--------
  6 | aaa    | bbb    | ccc    | ddd    | link_to_sub1_here | link_to_sub2_here |

如上所述,我是新手,找不到实现梦想的解决方案。拜托,这里的任何专家都可以给我一个灯。

在此感谢大家的建议和意见。最后我得到了它与下面的解决方案一起工作。

由于 table_main.main_a 列是 table_mainpkey,并且每个 [=17] 中有一个(不是 pkeyfkey)列=] 和 table_sub2table_main.main_a 具有相同的值。此外,值(如果有的话)首先到达 table_sub1table_sub2 ,然后到达 table_main(总是)。所以,我下面的触发函数完美地工作:

CREATE OR REPLACE FUNCTION save_data()
RETURNS trigger
AS $$
BEGIN
INSERT INTO table_copy (
copy_a,
copy_b,
copy_c,
copy_d)
VALUES ( 
NEW."main_a", 
NEW."main_b",
NEW."main_c",
NEW."main_d"
);
--Since value in table_sub1.sub_c is the same value in table_main.main_a
PERFORM sub_c FROM table_sub1 WHERE sub_c = NEW.main_a;
IF FOUND THEN UPDATE table_copy SET copy_e = ('link_to_sub1_here');
END IF;
--Since value in table_sub2.sub2_c is also the same value in table_main.main_a
PERFORM sub2_c FROM table_sub2 WHERE sub2_c = NEW.main_a;
IF FOUND THEN UPDATE table_copy SET copy_f = ('link_to_sub2_here');
END IF;
RETURN NEW;
END $$ LANGUAGE plpgsql;
ALTER FUNCTION save_data() OWNER TO postgres;
DROP TRIGGER trigger_save_data ON "table_main";
CREATE TRIGGER trigger_save_data BEFORE INSERT OR UPDATE 
ON "table_main" FOR EACH ROW EXECUTE PROCEDURE save_data();

这是测试结果:

postgres=# INSERT INTO table_sub2 VALUES ('cdef', 'abv', 'abcde', 'a12');
INSERT 0 1
postgres=# INSERT INTO table_sub1 VALUES ('cdeb', 'abv', 'abcde', 'a12');
INSERT 0 1
postgres=# INSERT INTO table_main (main_a, main_b, main_c, main_d) VALUES ('abcde', 'bbb', 'ccc', 'ddd');
INSERT 0 1
postgres=# SELECT * FROM table_copy;
 id | copy_a | copy_b | copy_c | copy_d |      copy_e       |      copy_f       | copy_g
----+--------+--------+--------+--------+-------------------+-------------------+--------
  6 | abcde  | bbb    | ccc    | ddd    | link_to_sub1_here | link_to_sub2_here |
(1 row)


postgres=#

只为需要的人提供解决方案。

干杯。