postgresql - 在函数中按列类型过滤行

标签 postgresql plpgsql

现在我有一个通用通知函数,在数据库中的几个表上创建后会触发该函数(另一端有一个节点进程正在监听通知)。我的更新触发器如下所示:

CREATE OR REPLACE FUNCTION notify_create() RETURNS trigger
  LANGUAGE plpgsql
  AS $$
BEGIN
  PERFORM pg_notify('update_watchers',
    json_build_object(
      'eventType', 'new',
      'type', TG_TABLE_NAME,
      'payload', row_to_json(NEW)
    )::text
  );
  RETURN NEW;
END;
$$;

问题是,如果 NEW 太大,在一些有限的极端情况下,这将溢出 8000 字节的限制(我很少在表中出现那么大的新项目)。在notify_update函数中,我只是通过列出列名来报告哪些列已更改。这在这里可行,但我宁愿做的只是让 row_to_json 从 NEW 中提取整数类型的条目。

那是因为有时我要通知的是“嘿实体表中有一个新条目”。新条目可能来自几个不同的表(文档、配置文件等)。在这种情况下,我实际上只需要 id,因为任何对新值感兴趣的人最终都会稍后获取它。

有时我会通知“嘿,连接表中有一个新条目”,在这种情况下,我没有 id 字段,而是有类似documents_id 和profiles_id 的内容。

可以为每个场景编写一堆不同的notify_create函数。我更喜欢有一个可以做类似事情的

row_to_json(NEW.filter(t => typeof t === 'number'))

将 plpgsql 和 javascript 表示法混合在一起,但我相信您明白了:只包含那些数字输入的 NEW 字段

这可能吗,还是我应该编写一堆不同的通知程序?

最佳答案

您可以轻松消除 number 以外类型的 json 对象,例如:

with my_table(int1, text1, int2, date1, float1) as (
values
    (1, 'text1', 100, '2017-01-01'::date, 123.54)
)

select jsonb_object_agg(key, value) filter (where jsonb_typeof(value) = 'number')
from my_table,
jsonb_each(to_jsonb(my_table))


              jsonb_object_agg              
--------------------------------------------
 {"int1": 1, "int2": 100, "float1": 123.54}
(1 row)

下面的函数只留下整数:

create or replace function leave_integers(jdata jsonb)
returns jsonb language sql as $$
    select jsonb_object_agg(key, value) 
    filter (
        where jsonb_typeof(value) = 'number'
        and value::text not like '%.%')
    from jsonb_each(jdata)
$$;

with my_table(int1, text1, int2, date1, float1) as (
values
    (1, 'text1', 100, '2017-01-01'::date, 123.54)
)

select leave_integers(to_jsonb(my_table))
from my_table;

      leave_integers      
--------------------------
 {"int1": 1, "int2": 100}
(1 row) 

替代(更好)的解决方案

此函数直接检查 Postgres 类型并严格从整数列返回值。

create or replace function integer_columns_to_jsonb(anyelement)
returns jsonb language sql as $$
    select jsonb_object_agg(key, value) 
    from jsonb_each(to_jsonb($1))
    where key in (
        select attname
        from pg_type t
        join pg_attribute on typrelid = attrelid
        where t.oid = pg_typeof($1)
        and atttypid = 'int'::regtype)
$$;

该示例显示该函数消除了 leave_integers() 错误处理的一些极端情况:

create table my_table (int1 int, int2 int, float1 float, text1 text);
insert into my_table values (1, 2, 3, '4');

select integer_columns_to_jsonb(t), leave_integers(to_jsonb(t))
from my_table t;

 integer_columns_to_jsonb |           leave_integers            
--------------------------+-------------------------------------
 {"int1": 1, "int2": 2}   | {"int1": 1, "int2": 2, "float1": 3}
(1 row)

关于postgresql - 在函数中按列类型过滤行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44079165/

相关文章:

sql - 后缀 : Using previous calculated value in WHERE clause

python - Django 保存点回滚捕获完整性错误导致 TransactionManagementError

带有匹配表达式的 PostgreSQL regexp_replace

linux - 由于 ALTER SYSTEM 设置错误而无法启动 postgres

sql - PostgreSQL LEFT OUTER JOIN 查询语法

ruby-on-rails - rails : Change my development database from sqlite to postgresql

arrays - 在 begin 和 end 中动态创建数组

sql - 如何通过 plpgsql 从 Postgres 获取表的主键?

sql - 通过来自不同未链接表的不同字段的连续循环

postgresql - 在 PostgreSQL GIN 索引中使用 JSON 对象值