使用数据库触发器更新 json 对象的键和条件

问题描述 投票:0回答:1

我有以下表格:

create table margins (
  id serial primary key,
  margins JSON,
  created_at TIMESTAMP NOT NULL,
  institution_uuid UUID NOT NULL,
  created_by VARCHAR
);

create table margin_defaults (
  id serial primary key,
  model VARCHAR(255) NOT NULL,
  margin FLOAT NOT NULL,
  created_by VARCHAR(255) NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

我将以下对象数组存储在列

margins
或表
margins

insert into margins (margins, created_at, institution_uuid, created_by) VALUES ('[{"model": "samsungS23","margin": "0.5","type": "CUSTOM"},{"model": "iphone",,"margin": "0.2","type": "CUSTOM"},{"model": "pixel","margin": "0.2","type": "CUSTOM"}]', '2023-12-12 15:38:40.642428', '51d8060e-5a31-4575-b56d-c5100e94d614', 'test-runner') RETURNING *;

margin_defaults
表中,我存储了不同类型边距的所有默认值。该表是追加/创建表,因此不会更新任何行。
margins
表也是如此。但是,当将新条目添加到
margin_defaults
表中时,我希望能够获取边距表中每个
institution_uuid
的最后一组条目,并使用相同的
 更新 
margins
 列中的相应对象type
与新的
margin_defauts
条目相同,但仅当当前边距
type
设置为
DEFAULT
时。

到目前为止,我已经提出了以下触发器,但我收到了此错误:

ERROR:  function jsonb_set(jsonb, text[], double precision) does not exist
LINE 3:      jsonb_set(r.margins::jsonb, ('{' || tmp_position || ',m...
             ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
QUERY:  INSERT INTO margins (institution_uuid, margins, created_by) VALUES (
                    r.institution_uuid,
                    jsonb_set(r.margins::jsonb, ('{' || tmp_position || ',margin}')::text[], NEW.margin)::json,
                    NEW.created_by
                )
CONTEXT:  PL/pgSQL function update_margins_default_values_function() line 10 at SQL statement

我的触发点:

CREATE OR REPLACE FUNCTION update_margins_default_values_function()
RETURNS TRIGGER AS $$
DECLARE r RECORD;
DECLARE tmp_position int;
BEGIN
        FOR r IN
                SELECT DISTINCT ON (b.institution_uuid) * FROM (SELECT DISTINCT ON (institution_uuid) * FROM margins ORDER BY institution_uuid, created_at DESC) as b WHERE b.margins::jsonb@>'[{"type":"DEFAULT"}]' ORDER BY institution_uuid
        LOOP
            SELECT position FROM jsonb_array_elements(r.margins::jsonb) with ordinality arr(elem, position) INTO tmp_position WHERE elem->>'model'=NEW.model AND elem->>'type'='DEFAULT';
            IF found THEN
                INSERT INTO margins (institution_uuid, margins, created_by) VALUES (
                    r.institution_uuid,
                    jsonb_set(r.margins::jsonb, ('{' || tmp_position || ',margin}')::text[], NEW.margin)::json,
                    NEW.created_by
                );
            END IF;
        END LOOP;
    RETURN 1;
END;
$$ LANGUAGE plpgsql;


CREATE OR REPLACE TRIGGER update_margins_default_values_trigger
    AFTER INSERT ON margin_defaults FOR EACH ROW EXECUTE PROCEDURE update_margins_default_values_function();

我正在尝试工作的小提琴 - sqlFiddle

json postgresql triggers
1个回答
0
投票

试试这个..我修改了触发器函数,以正确更新

margins
表中JSON数组中的特定元素,使用带有动态构造路径的
jsonb_set
函数并将新的边距值转换为
jsonb

CREATE OR REPLACE FUNCTION update_margins_default_values_function()
RETURNS TRIGGER AS $$
DECLARE 
    r RECORD;
    tmp_position int;
    new_margin jsonb;
BEGIN
    FOR r IN
            SELECT DISTINCT ON (m.institution_uuid) m.* FROM margins m WHERE m.margins::jsonb @> '[{"type":"DEFAULT"}]' ORDER BY m.institution_uuid, m.created_at DESC
    LOOP
        SELECT position FROM jsonb_array_elements(r.margins::jsonb) WITH ORDINALITY arr(elem, position)
        INTO tmp_position
        WHERE elem->>'model' = NEW.model AND elem->>'type' = 'DEFAULT';

        IF FOUND THEN
            new_margin := to_jsonb(NEW.margin::text); 
            INSERT INTO margins (institution_uuid, margins, created_by) VALUES (
                r.institution_uuid,
                jsonb_set(r.margins::jsonb, ARRAY[tmp_position::text, 'margin'], new_margin),
                NEW.created_by
            );
        END IF;
    END LOOP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;
© www.soinside.com 2019 - 2024. All rights reserved.