[英]How to efficiently update postgres using a tuple of the PK and a value?
[英]Using postgres triggers to update tag counts efficiently
我有一个架构,其中用户具有与其关联的标签:
user_id: int4 tags: text[]
------------- ------------
1 [ 'apple', 'carrot', 'jelly' ]
2 [ 'jelly', 'zebra' ]
我正在寻找创建返回所有标签列表及其相关计数的查询。 例子:
tag: text count: int4
--------- -----------
'apple' 1
'carrot' 1
'jelly' 2
'zebra' 1
触发器似乎是实现此目的的理想方式,因为该应用程序是重读和轻写。
但是,我很难实现这一点。 我认为触发器本身似乎很简单:
CREATE TRIGGER tags_count_update
AFTER UPDATE OF tags ON person
FOR EACH ROW
EXECUTE PROCEDURE trigger_update_tags_count();
trigger_update_tags_count
是我遇到问题的部分,因为它似乎是一个非常复杂的操作。 例如,如果tags
表中尚不存在该tags
,则应将其插入,计数为 1。
另外,我相信您需要进行某种差异操作,因为如果某人的标签从[ 'apple', 'carrot', 'jelly' ]
为[ 'apple', 'dogs' ]
那么apple
的计数不会不变, carrot
and jelly
减1,创建dogs
将其计数设置为1。这与标签是数组的事实相结合。 我目前有这样的事情:
CREATE OR REPLACE FUNCTION public.trigger_update_tags_count()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
INSERT INTO tags (tag, count) VALUES (new.tag, 1)
ON CONFLICT (tag) DO UPDATE
SET count = CASE WHEN (tag.new AND NOT tag.old) THEN count + 1
WHEN (tag.old AND NOT tag.new) THEN count - 1
ELSE count
END
RETURN NEW;
END;
$function$;
这有点伪代码,因为我不确定如何整合我正在处理文本数组的事实,也不知道如何处理不同的情况。
你在数据中没有任何叫做tag
东西; 它是tags
。 所以你需要UNNEST()
并处理旧标签和新标签。 我在想这样的事情:
INSERT INTO tags (tag, count)
SELECT COALESCE(ntag, otag),
(ntag IS NOT NULL)::int - (otag IS NOT NULL)::int
FROM UNNEST(new.tags) ntag FULL JOIN
UNNEST(old.tags) otag
ON ntag = otag
ON CONFLICT (tag) DO UPDATE
SET count = count + (excluded.ntag IS NOT NULL)::int - (excluded.otag IS NOT NULL)::int
我不确定您是否需要为此触发复杂的逻辑。 您可以通过利用Postgres 数组函数unnest()
的简单查询获得所需的输出:
select x.tag, count(*)
from mytable t
cross join lateral unnest(t.tags) x(tag)
group by x.tag
请注意,如果您发现自己重复运行此类查询,则表明您的设计并不真正适合您的用例; 您最好将每个user_id/tag
元组存储在单独的表行中,与存储用户的表分开。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.