PostgreSQL触发器报错record "new" has no field "i_produtos"如何解决
报错原因
你的触发器绑定在fabricante表上,触发器内的NEW、OLD关键字对应fabricante表触发更新时的新、旧行数据,而fabricante表本身不存在i_produtos字段,因此调用NEW.i_produtos会直接抛出字段不存在的错误。
同时你的触发逻辑也存在关联错误:你要判断当前修改的厂商是否有已销售的关联商品,需要先通过厂商ID关联到商品表,再关联销售记录,而不是直接引用商品ID。
修复方案
假设你的业务需求是如果某个厂商已经有对应商品产生了销售记录,就不允许修改该厂商的i_fabricantes字段,修正后的触发函数代码如下:
CREATE OR REPLACE FUNCTION alter_fab() RETURNS TRIGGER AS $alter_fab$ BEGIN -- 仅当i_fabricantes字段被修改时才执行校验 IF OLD.i_fabricantes != NEW.i_fabricantes AND EXISTS( SELECT * FROM item i INNER JOIN venda ON venda.i_vendas = i.i_vendas -- 先关联商品表,找到属于当前修改厂商的所有商品 INNER JOIN produtos p ON p.i_produtos = i.i_produtos WHERE p.i_fabricantes = OLD.i_fabricantes ) THEN RAISE EXCEPTION 'Fabricante não pode ser alterado!'; END IF; -- 行级BEFORE触发器必须返回新行数据 RETURN NEW; END; $alter_fab$ LANGUAGE plpgsql;
调整说明
- 修正了子查询的关联逻辑:通过旧的厂商ID
OLD.i_fabricantes关联商品表,再关联销售记录,避免引用不存在的字段 - 补充了必须的
RETURN NEW语句,否则触发器执行完成后会抛出无返回值的错误 - 原有触发器创建代码无需修改,可正常使用
可选场景说明
如果你的实际需求是不允许修改商品所属的厂商,当该商品已经产生销售记录,则需要把触发器绑定在produtos表上,触发函数的判断逻辑可以简化为:
IF OLD.i_fabricantes != NEW.i_fabricantes AND EXISTS( SELECT * FROM item i INNER JOIN venda ON venda.i_vendas = i.i_vendas WHERE i.i_produtos = NEW.i_produtos ) THEN RAISE EXCEPTION 'Fabricante não pode ser alterado!'; END IF;
内容的提问来源于stack exchange,提问作者Oppo
相关产品推荐
相关产品推荐

