Sql 如何根据其他表中属性的更改触发表中某行中属性的更新?

Sql 如何根据其他表中属性的更改触发表中某行中属性的更新?,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

我有一个表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      | 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
的情况下避免这种情况。我认为必须为此设置一个标志栏,那么?再次感谢。我现在接受了另一个答案,因为它解决了我的问题,而且很简单。然而,我从这个答案中学到了很多关于触发器、视图和函数的知识。感谢您的努力和时间!对不起&谢谢!