在Postgres中,我试图从父级继承其子级的唯一属性。父表是一个抽象表,其中没有条目。所有孩子的名字都应该是独一无二的。参考下面的小(愚蠢)例子:应该没有与香蕉同名的苹果(当然还有其他苹果)。
这个场景的Minimalistic Postgres示例:
CREATE TABLE fruit(CONSTRAINT fruit_uniq_name UNIQUE (name))
CREATE TABLE banana(name text, length integer) INHERITS (fruit)
CREATE TABLE apple(name, diameter integer NOT NULL,) INHERITS (fruit)
在阅读了很多关于这个问题的帖子之后。所有这些人都得出结论,只有Postgres的继承才能掌握这种情况,我想知道是否有最佳实践解决方法,例如:使用触发器和函数,针对这个问题?
我会为每一小段代码感到高兴,这可以帮助我摆脱这个烦人的陷阱。
我遵循Laurenz Albe的建议,我认为我通过在表apple和banana上使用触发器以及测试唯一性的触发器函数tgf_name_exists()
来解决问题。
这是测试子名称唯一性的触发器函数:
CREATE OR REPLACE FUNCTION tgf_name_exits()
RETURNS trigger
LANGUAGE 'plpgsql'
VOLATILE
COST 100
AS $BODY$
declare
count_apple integer;
count_banana integer;
name text;
schema text;
error_text text;
BEGIN
-- Variables
error_text = '';
schema = TG_TABLE_SCHEMA; -- actual schema
name = NEW.name; --- actual attribute name
-- Check
EXECUTE format('SELECT count(*) FROM %s.apple apl WHERE apl.name=%L', schema, name) INTO count_apple;
EXECUTE format('SELECT count(*) FROM %s.banana ban WHERE ban.name=%L', schema, name) INTO count_banana;
-- Info
RAISE NOTICE 'Schema: %', schema;
RAISE NOTICE 'Name: %', name;
RAISE NOTICE 'Count: %', count_apple;
RAISE NOTICE 'Count: %', count_banana;
IF count_apple > 0 OR count_banana > 0 THEN
-- Name ist already used
if count_apple > 0 then
error_text = error_text || "apple "
end if;
if count_banana > 0 then
error_text = error_text || "banana "
end if;
RAISE EXCEPTION 'Name % already existing in table %', name, error_text;
ELSE
-- Name is unused -> OK
RETURN NEW;
END IF;
END;
$BODY$;
这些是苹果和香蕉表的触发器
CREATE TRIGGER tg_apple_name_instert_update
BEFORE INSERT OR UPDATE
ON apple
FOR EACH ROW
EXECUTE PROCEDURE tgf_name_exits();
CREATE TRIGGER tg_banana_name_uniq
BEFORE INSERT OR UPDATE
ON banana
FOR EACH ROW
EXECUTE PROCEDURE tgf_name_exits();
如果有人能检查这个,那将是非常友好的。从这里看起来它很有效。