我需要检查jsonb中的值是否已存在于数组中。我试图通过触发器实现这一点,但我是这种语言的新手,我不知道如何编写查询。
CREATE TABLE merchants (
key uuid PRIMARY KEY,
data jsonb NOT NULL
)
这是触发器。我认为NEW.data.ids部分是错误的。
CREATE FUNCTION validate_id_constraint() returns trigger as $$
DECLARE merchants_count int;
BEGIN
merchants_count := (SELECT count(*) FROM merchants WHERE data->'ids' @> NEW.data.ids);
IF (merchants_count != 0) THEN
RAISE EXCEPTION 'Duplicate id';
END IF;
RETURN NEW;
END;
$$ language plpgsql;
CREATE TRIGGER validate_id_constraint_trigger BEFORE INSERT OR UPDATE ON merchants
FOR EACH ROW EXECUTE PROCEDURE validate_id_constraint();
当我插入表格时,我收到此错误消息
ERROR: missing FROM-clause entry for table "data"
LINE 1: ...LECT count(*) FROM merchants WHERE data->'ids' @> NEW.data.i...
^
我已经在触发器外完成了查询,并且工作正常
SELECT count(*) FROM merchants WHERE data->'ids' @> '["11176", "11363"]'
答案 0 :(得分:1)
您收到该错误是因为您使用.
而不是->
来提取表达式ids
中的NEW.data.ids
数组。
但是你的触发器无论如何都不会起作用,因为你并没有试图避免遏制,而是在阵列中重叠。
您可以编写触发器功能的一种方法是:
CREATE OR REPLACE FUNCTION validate_id_constraint() RETURNS trigger
LANGUAGE plpgsql AS
$$DECLARE
j jsonb;
BEGIN
FOR j IN
SELECT jsonb_array_elements(NEW.data->'ids')
LOOP
IF EXISTS
(SELECT 1 FROM merchants WHERE j <@ (data->'ids'))
THEN
RAISE EXCEPTION 'Duplicate IDs';
END IF;
END LOOP;
RETURN NEW;
END;$$;
您必须循环,因为jsonb
数组上没有“重叠”运算符。
由于你的桌面设计,这一切都很慢而且很麻烦。
注1:如果只在jsonb
中存储不需要在数据库中操作的数据,那么 会更好。特别是,您应该将ids
数组存储为表中的字段。然后,您可以使用“重叠”运算符&&
,并使用gin
索引加快速度。
如果对表结构进行规范化并将单个数组条目存储在单独的表中,那么你会更快。然后是常规的唯一约束。
注2:触发器启用的任何约束都会遇到竞争条件:如果两个并发的INSERT
相互冲突,则触发器函数将看不到并发的值INSERT
,您可能会得到不一致的数据。