【发布时间】:2018-03-06 09:24:03
【问题描述】:
这是我的问题的示例:http://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=ddb9cfd2da315ecf36cfffd66853f023
我使用这个功能:
CREATE OR REPLACE FUNCTION inListExistOrNull(list jsonb) RETURNS boolean AS
$BODY$
DECLARE
r TEXT;
i boolean := false;
vcount int;
BEGIN
FOR r IN SELECT * FROM jsonb_array_elements($1) LOOP
vcount := (SELECT COUNT(*)
FROM table_example
WHERE data->>'test' LIKE '%' || r || '%');
i := vcount > 0;
IF i = true THEN
EXIT;
END IF;
END LOOP;
IF i = true THEN
RETURN true;
END IF;
RETURN NULL;
END;
$BODY$
LANGUAGE 'plpgsql'
IMMUTABLE
RETURNS NULL ON NULL INPUT;
我这样创建一个表和索引:
CREATE TABLE IF NOT EXISTS table_example(
id bigserial primary key,
data jsonb,
txid bigint
);
CREATE INDEX IF NOT EXISTS table_example_txid_index
ON table_example(txid);
CREATE UNIQUE INDEX IF NOT EXISTS unique_table_example
ON table_example(inListExistOrNull(data->'test'));
我插入了一些行:
INSERT INTO table_example (id, data, txid)
VALUES (1, '{"test": ["https://example.com/test/123", "https://example.com/test/678"]}', 1);
INSERT INTO table_example (id, data, txid)
VALUES (2, '{"test": ["https://example.com/test/b4b81fb221d4fa641", "https://example.com/test/624f3e10048245fb1"]}', 2);
INSERT INTO table_example (id, data, txid)
VALUES (4, '{"test": ["https://example.com/test/ggg", "https://example.com/test/hhh"]}', 4);
INSERT INTO table_example (id, data, txid)
VALUES (5, '{"test": ["https://example.com/test/ggg"]}', 5);
我不知道为什么我可以用id = 5 创建一行。它应该被唯一索引捕获,但事实并非如此。
这就像我期望的那样工作:
INSERT INTO table_example (id, data, txid)
VALUES (6, '{"test": ["https://example.com/test/b4b81fb221d4fa641", "https://example.com/test/624f3e10048245fb1"]}', 6);
ERROR: duplicate key value violates unique constraint "unique_table_example"
DETAIL: Key (inlistexistornull(data -> 'test'::text))=(t) already exists.
解决方案
触发:
CREATE OR REPLACE FUNCTION inListExistOrNull() RETURNS TRIGGER AS
$BODY$
DECLARE
r TEXT;
i boolean := false;
vcount int;
newData jsonb;
BEGIN
newData := NEW.data->'test';
FOR r IN SELECT * FROM jsonb_array_elements(newData) LOOP
vcount := (SELECT COUNT(*) FROM table_example WHERE data->>'test' LIKE '%' || r || '%');
i := vcount > 0;
IF i = true THEN
RAISE 'Duplicate data: %', r USING ERRCODE = '23505';
END IF;
END LOOP;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql'
STABLE;
CREATE TRIGGER inListExistOrNullTrigger
BEFORE INSERT OR UPDATE ON table_example
FOR EACH ROW EXECUTE PROCEDURE inListExistOrNull();
唯一索引:
CREATE OR REPLACE FUNCTION inListExistOrNull(list jsonb) RETURNS int AS
$BODY$
DECLARE
r TEXT;
i boolean := false;
vcount int;
BEGIN
FOR r IN SELECT * FROM jsonb_array_elements($1) LOOP
vcount := (SELECT COUNT(*) FROM table_example WHERE data->>'test' LIKE '%' || r || '%');
i := vcount > 0;
IF i = true THEN
RAISE 'Duplicate data: %', r USING ERRCODE = '23505';
END IF;
END LOOP;
IF i = true
THEN
RETURN true;
ELSE
RETURN NULL;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql'
IMMUTABLE
RETURNS NULL ON NULL INPUT;
CREATE UNIQUE INDEX IF NOT EXISTS unique_table_example ON table_example(inListExistOrNull(data->'test'));
【问题讨论】:
-
为什么不简单地规范化您的模型并创建适当的唯一索引?