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)
);
我的目的是:
- 将数据从 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)
- 我的第二个(也是更重要的)目的是根据
table_sub1
和 [=21] 的条件将自定义字符串插入 table_copy 的最后几列(当然是在同一行) =],例如,IF table_sub1.sub_c
或 table_sub2.sub2_d
已插入值,自定义字符串 (links) 将分别插入 table_copy.copy_e
或 table_copy.copy_f
。
我尝试了下面的一些解决方案,但都不让我满意。
解决方案 1:在 table_main
、table_sub1
和 table_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_main
的 pkey
,并且每个 [=17] 中有一个(不是 pkey
或 fkey
)列=] 和 table_sub2
与 table_main.main_a
具有相同的值。此外,值(如果有的话)首先到达 table_sub1
和 table_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=#
只为需要的人提供解决方案。
干杯。
拜托,我是 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)
);
我的目的是:
- 将数据从 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)
- 我的第二个(也是更重要的)目的是根据
table_sub1
和 [=21] 的条件将自定义字符串插入 table_copy 的最后几列(当然是在同一行) =],例如,IFtable_sub1.sub_c
或table_sub2.sub2_d
已插入值,自定义字符串 (links) 将分别插入table_copy.copy_e
或table_copy.copy_f
。
我尝试了下面的一些解决方案,但都不让我满意。
解决方案 1:在 table_main
、table_sub1
和 table_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_main
的 pkey
,并且每个 [=17] 中有一个(不是 pkey
或 fkey
)列=] 和 table_sub2
与 table_main.main_a
具有相同的值。此外,值(如果有的话)首先到达 table_sub1
和 table_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=#
只为需要的人提供解决方案。
干杯。