如何让PostgreSQL继承表的外键仅引用自身主键而非其他继承表?
问题与解决方法
现有表结构
父表 payments
CREATE TABLE payments ( id bigserial NOT NULL PRIMARY KEY, method int, method_name name, total numeric, payment_date timestamp without time zone, is_seccessful boolean, data jsonb );
继承表 subscription_payments
CREATE TABLE subscription_payments ( subscription_id int, parent_id bigint, CONSTRAINT pk_subscription_id FOREIGN KEY (subscription_id) REFERENCES subscriptions (id) ON DELETE RESTRICT ) INHERITS (payments);
需求
要给subscription_payments的parent_id添加外键约束,让它仅引用自身表的id,不能关联payments父表或其他继承自payments的子表。
解决方案
最简单的正确写法
直接创建指向subscription_payments自身的外键即可,PostgreSQL会自动限定只关联该表的记录,不会涉及整个继承树:
ALTER TABLE subscription_payments ADD CONSTRAINT fk_sub_payments_parent_id FOREIGN KEY (parent_id) REFERENCES subscription_payments(id) ON DELETE RESTRICT; -- 这里的删除规则可根据业务需求调整,比如改为CASCADE、SET NULL
关键注意点
千万别写REFERENCES payments(id),否则parent_id不仅能引用subscription_payments的id,还能关联payments父表,甚至以后新建的其他继承payments的表(比如order_payments)的id,完全不符合“仅引用自身”的要求。
备选方案:触发器验证
如果需要更复杂的校验逻辑,可以用触发器实现:
-- 创建触发器函数,检查parent_id对应的记录是否在subscription_payments内 CREATE OR REPLACE FUNCTION check_parent_id_in_self() RETURNS TRIGGER AS $$ BEGIN IF NOT EXISTS (SELECT 1 FROM subscription_payments WHERE id = NEW.parent_id) THEN RAISE EXCEPTION 'parent_id必须指向subscription_payments表中的记录'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; -- 绑定触发器,插入或更新parent_id时触发检查 CREATE TRIGGER trigger_check_parent_id BEFORE INSERT OR UPDATE OF parent_id ON subscription_payments FOR EACH ROW EXECUTE FUNCTION check_parent_id_in_self();
内容的提问来源于stack exchange,提问作者Salih Kavaf
相关产品推荐
相关产品推荐

