Postgresql 如何在触发器函数中使用json字符串元素而不将其声明为变量

Postgresql 如何在触发器函数中使用json字符串元素而不将其声明为变量,postgresql,postgresql-11,Postgresql,Postgresql 11,我正在学习Postgresql——我没有想到具体的应用程序,但总体思路是用json更新一列,而不用担心其他列 我有一个带有几列(id、name、amount、json)的表。我只想更新json列,并使用触发器更新json中的其他列 例如,如果json设置为{“name”=“fred”,“amount”=100},则触发器将填充name和amount列 到目前为止,这是可行的: create table one(id serial primary key, name text, amount in

我正在学习Postgresql——我没有想到具体的应用程序,但总体思路是用json更新一列,而不用担心其他列

我有一个带有几列(id、name、amount、json)的表。我只想更新json列,并使用触发器更新json中的其他列

例如,如果json设置为{“name”=“fred”,“amount”=100},则触发器将填充name和amount列

到目前为止,这是可行的:

create table one(id serial primary key, name text, amount int, data jsonb);
我尝试在不声明任何变量的情况下执行此操作。例如,我尝试了以下方法:

IF one.data->'name' IS DISTINCT FROM OLD.name THEN

但都不管用

制作这样一个触发器可能是一个可怕的想法,知道这一点很好,但我主要感兴趣的是弄清楚json的内容:)

我在这里举了一个例子:


将其作为一个before触发器,而不是
UPDATE
操作
new

CREATE OR REPLACE FUNCTION test()
                  RETURNS trigger
AS
$$
BEGIN
  new.name := new.data->'name';
  new.amount := new.data->'amount';

  RETURN new;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER test_trigger
               BEFORE INSERT
                      OR UPDATE
                         OF data
               ON one
               FOR EACH ROW
               EXECUTE PROCEDURE test();

尽管@sticky bit提供的答案方向正确,但它不能很好地处理类型转换

下面是一个更适合处理空JSON字符串的版本:

创建或替换功能测试()
将触发器返回为
$$
开始
NEW.name:=(NEW.data->>'name');
NEW.amount:=四舍五入((NEW.data->>'amount')::数字)::int;
归还新的;
结束;
$$
语言“plpgsql”;
创建触发器测试\u触发器
在插入或更新之前
一台计算机上的数据传输
每行
执行过程测试();


请记住,在原始的
INSERT
UPDATE
之后,在触发器函数中执行多个
UPDATE
会降低性能。

哦,这太棒了!我对以前使用的
感到困惑,比如说,没有发生的事情怎么会触发某些事情。是否正确:事件已启动,但在更新表之前触发函数,然后函数只更新一次所有内容?而
AFTER
允许表更新,然后该函数再次更新。。。为了两次更新?无论如何,谢谢-这正是我所希望的答案,还有更多!是的,你基本上是对的。使用
BEFORE
,我们实际上可以在执行实际更改之前修改查询中的数据行(
NEW
)。这是基于行(O)的RDBMS的优点之一。在纯基于列的(O)(R)DBMS中,这将是一场性能噩梦
IF one.data->'name'::text IS DISTINCT FROM OLD.name THEN
IF ((data->'name') from one) IS DISTINCT FROM OLD.name THEN
CREATE OR REPLACE FUNCTION test()
                  RETURNS trigger
AS
$$
BEGIN
  new.name := new.data->'name';
  new.amount := new.data->'amount';

  RETURN new;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER test_trigger
               BEFORE INSERT
                      OR UPDATE
                         OF data
               ON one
               FOR EACH ROW
               EXECUTE PROCEDURE test();