Sql 如何根据其他表中属性的更改触发表中某行中属性的更新?
我有一个表a、表B和一个联接表a_B 表ASql 如何根据其他表中属性的更改触发表中某行中属性的更新?,sql,postgresql,Sql,Postgresql,我有一个表a、表B和一个联接表a_B 表A | id | a_active | | -- | -------- | | a1 | true | 表B | id | b_active | | -- | -------- | | b1 | false | 表A_B-主键唯一(A_id,B_id)和外键分别引用A和B | id | a_id_fk | b_id_fk | active | | -- | ------- | ------- | ------ | | j1 | a1
| id | a_active |
| -- | -------- |
| a1 | true |
表B
| id | b_active |
| -- | -------- |
| b1 | false |
表A_B-主键唯一(A_id
,B_id
)和外键分别引用A和B
| id | a_id_fk | b_id_fk | active |
| -- | ------- | ------- | ------ |
| j1 | a1 | b1 | false |
因此,每当a_active
或b_active
的值发生变化时,我希望active
根据条件a_active&&b_active
进行变化
此外,我应该能够将active
更改为false
,但要更改为true
,它应该执行上述检查
我一直在研究触发器,觉得它可能会帮助我处理这个用例,但我不知道如何处理它。请提供帮助。推荐的方法是编写如下视图:
create view viewA_B as
select
t1.id,t1.a_id_fk,t1.b_id_fk, ((t2.a_active) and (t3.b_active)) "active"
from a_b t1
inner join tabA t2 on t2.id=t1.a_id_fk
inner join tabB t3 on t3.id=t1.b_id_fk
select * from viewA_B where active=false;
CREATE OR REPLACE FUNCTION validate_active(id_a varchar, id_b varchar,val bool)
RETURNS BOOLEAN AS $$
declare check_b bool;
declare check_a bool;
begin
select a_active into check_a from tabA where id=id_a;
select b_active into check_b from tabB where id=id_b;
if val then
return (check_b and check_a);
else
return true;
end if;
end;
$$ LANGUAGE plpgsql;
alter table a_b add CONSTRAINT valid_val CHECK(validate_active(a_id_fk,b_id_fk,active))
然后,您可以使用如下视图:
create view viewA_B as
select
t1.id,t1.a_id_fk,t1.b_id_fk, ((t2.a_active) and (t3.b_active)) "active"
from a_b t1
inner join tabA t2 on t2.id=t1.a_id_fk
inner join tabB t3 on t3.id=t1.b_id_fk
select * from viewA_B where active=false;
CREATE OR REPLACE FUNCTION validate_active(id_a varchar, id_b varchar,val bool)
RETURNS BOOLEAN AS $$
declare check_b bool;
declare check_a bool;
begin
select a_active into check_a from tabA where id=id_a;
select b_active into check_b from tabB where id=id_b;
if val then
return (check_b and check_a);
else
return true;
end if;
end;
$$ LANGUAGE plpgsql;
alter table a_b add CONSTRAINT valid_val CHECK(validate_active(a_id_fk,b_id_fk,active))
但你还是想写触发器。然后你必须写2个触发器。一个在表A上,第二个在表B上。用这个
表A的触发函数
CREATE OR REPLACE FUNCTION updateA()
RETURNS TRIGGER
AS
$$
BEGIN
update a_b t1
SET "active" = (new.a_active and t2.b_active)
from tabB t2 where t2.id=t1.b_id_fk and t1.a_id_fk=NEW.id;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
表A上的触发器
CREATE TRIGGER trg_update_a
AFTER UPDATE ON tabA
FOR EACH ROW
EXECUTE PROCEDURE updateA();
表B的触发函数
CREATE OR REPLACE FUNCTION updateB()
RETURNS TRIGGER
AS
$$
BEGIN
update a_b t1
SET "active" = (new.b_active and t2.a_active)
from tabA t2 where t2.id=t1.a_id_fk and t1.b_id_fk=NEW.id;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
表B上的触发器
CREATE TRIGGER trg_update_b
AFTER UPDATE ON tabB
FOR EACH ROW
EXECUTE PROCEDURE updateB();
编辑:根据评论
您希望在a_b
中验证更新,然后可以使用check
约束
首先创建一个如下所示的函数:
create view viewA_B as
select
t1.id,t1.a_id_fk,t1.b_id_fk, ((t2.a_active) and (t3.b_active)) "active"
from a_b t1
inner join tabA t2 on t2.id=t1.a_id_fk
inner join tabB t3 on t3.id=t1.b_id_fk
select * from viewA_B where active=false;
CREATE OR REPLACE FUNCTION validate_active(id_a varchar, id_b varchar,val bool)
RETURNS BOOLEAN AS $$
declare check_b bool;
declare check_a bool;
begin
select a_active into check_a from tabA where id=id_a;
select b_active into check_b from tabB where id=id_b;
if val then
return (check_b and check_a);
else
return true;
end if;
end;
$$ LANGUAGE plpgsql;
alter table a_b add CONSTRAINT valid_val CHECK(validate_active(a_id_fk,b_id_fk,active))
然后更改表格并添加如下检查约束:
create view viewA_B as
select
t1.id,t1.a_id_fk,t1.b_id_fk, ((t2.a_active) and (t3.b_active)) "active"
from a_b t1
inner join tabA t2 on t2.id=t1.a_id_fk
inner join tabB t3 on t3.id=t1.b_id_fk
select * from viewA_B where active=false;
CREATE OR REPLACE FUNCTION validate_active(id_a varchar, id_b varchar,val bool)
RETURNS BOOLEAN AS $$
declare check_b bool;
declare check_a bool;
begin
select a_active into check_a from tabA where id=id_a;
select b_active into check_b from tabB where id=id_b;
if val then
return (check_b and check_a);
else
return true;
end if;
end;
$$ LANGUAGE plpgsql;
alter table a_b add CONSTRAINT valid_val CHECK(validate_active(a_id_fk,b_id_fk,active))
上面将根据您的情况检查表a_b
中字段active
的更改。
如果您只需要活动数据(我认为这是您的意图),请使用: 使用此信息存储冗余列an
a_b
几乎没有什么好处。当a
或b
中的数据发生更改时,它会增加开销——实际上,可能会有很多更改。它使每一列稍微宽一点,因此表占用更多的空间。和a
和b
的连接应该非常快
编辑:
根据您的评论,您有三个活动标志,因此where
将是:
where a.active and b.active and ab.active
你可以用扳机来维持这个。但是为什么要麻烦呢?为什么不直接使用
join
,使值始终是最新的。@GordonLinoff我想仅基于活动的查询A_B。那么,避免加入不是更好吗?这些值不会经常更改。与其单独更新表,不如创建一个视图a_B
。“此外,我应该能够将active更改为false,但要更改为true,它应该执行上述检查。”因此,如果手动将a_B.active设置为false,但随后a_active更改为false,然后再次返回true,a_b.active是否也应自动更改为true?或者它必须记住它是手动覆盖的吗?@jjanes我现在明白你的问题了,所以我删除了我之前的评论,我误解了它,可能会让你感到困惑。>它必须记住它是手动覆盖的吗?是的,我更喜欢这样。你是对的,但是对于我的用例,a_b
中的active
可以是false
(直接更新active
中的a_b
),而不管a_active
和b_active
都是真的。请检查我最后的第二点。@ManpreetKrishan。这只是意味着您需要一个额外的标志,而不是应该使用触发器来维护它。我接受了您的回答,因为它涵盖了我的用例的各个方面。朴素典雅。我不太熟悉触发器,认为它们会帮助我的用例,连接是不好的。所以这只是模糊了我的想法,因此我一开始无法理解你的答案,在编辑之后(你错过了我的另一个用例),它完美地回答了我的问题。再次感谢!这有助于触发。但这并不能解决我不能将a_b.active更改为true的部分,如果a或b中的任何一个值为false。编辑:>此外,我应该能够将active更改为false,但要更改为true,它应该执行上述检查。编辑了答案并添加了所需的更改。这解决了我的用例。谢谢但是,假设我手动将a\u b.active
转换为false
,a\u active
更改为false
,然后true
,如果b.active
为true
,这将触发a\u b.active
并更新为true
。我希望在手动过渡到false
的情况下避免这种情况。我认为必须为此设置一个标志栏,那么?再次感谢。我现在接受了另一个答案,因为它解决了我的问题,而且很简单。然而,我从这个答案中学到了很多关于触发器、视图和函数的知识。感谢您的努力和时间!对不起&谢谢!