[英]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.