【发布时间】:2015-11-25 15:40:54
【问题描述】:
拜托,我是 PostgreSQL/PLPGSQL 的新手,我曾尝试在 Google 上到处搜索 SO,但找不到具体的解决方案。如果这个问题被重复,我深表歉意。
我想创建可以从 table_main 插入值的触发函数,如果其他子表有值,自定义字符串(链接)将插入到与 table_main 中的数据一致的同一行中。
我有 3 个由应用程序自动生成的表,类似于:
-- 主表
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_main 和自定义字符串(链接)复制的数据,如下所示:
-- 表格复制
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)
);
我的目的是:
- 当一条记录插入到 table_main 时,使用下面的触发器函数将数据从 table_main 复制到 table_copy,它工作正常:
.
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)
- 我的第二个(也是更重要的)目的是将自定义字符串插入到 table_copy 的最后几列(当然是在同一行),条件基于
table_sub1和table_sub2,例如,IFtable_sub1.sub_c或table_sub2.sub2_d插入了值,自定义字符串(链接)分别插入table_copy.copy_e或table_copy.copy_f。
我尝试了以下一些解决方案,但都不能让我满意。
解决方案1:在table_main、table_sub1和table_sub2的每个表上设置每个触发器。结果:它在table_copy 中创建了三行 ==> 不接受。
触发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 |
如上所述,我是新手,无法找到实现梦想的解决方案。拜托,这里的任何专家都可以给我一个亮点。
【问题讨论】:
-
您能否向我们展示一些带有插入序列的示例数据以及您期望得到的结果。你的问题很好,但还有改进的余地,请阅读How to ask 和How to create a Minimal, Complete, and Verifiable example. 这是一个很好的起点spaghettidba.com/2015/04/24/…
-
@Juan Carlos Oropeza:非常感谢您的及时反馈。我已经更新了我的问题。请帮忙。
-
您在函数中缺少的是 table_main 和 table_sub1 和 2 上的注册表之间的链接。为了使您的解决方案正常工作,现在应该以某种方式更改 ID(os 一些可识别的列)在 table_copy 上,否则你会遇到问题,你有插入应该更新函数 save_data_sub1() 和 save_data_sub2()
-
@Jorge Campos:非常感谢。但是,您的建议对我来说很新。能否请您进一步详细说明这件事,或者给我一些带有链接的示例,以便我学习。
-
没有关于
table_main和table_sub1等中的行如何连接的信息。通常,您将拥有某种形式的foreign keys(正式声明或未声明)。也没有关于在每个表中输入行的顺序的信息,也没有关于可能的更新或并发访问的信息。该问题在当前状态下无法回答。
标签: postgresql plpgsql