【问题标题】:How to access a column inside a stored procedure that is going to be used in a trigger? | PostgreSQL如何访问将在触发器中使用的存储过程中的列? | PostgreSQL
【发布时间】:2019-09-02 13:19:57
【问题描述】:

我正在尝试访问将由触发器调用的函数(= 存储过程)内表 tb_client_cdc 的列,以存储应用的操作(更新、插入、删除)的最后状态到表 tb_client。

如果我们在 tb_client 中进行 INSERT 并且该行存在于 tb_client_cdc 中,我们不必插入另一行,相反,我们必须更新该行。

所以,为了检测该行是否存在,我使用了:

IF ((TG_OP = 'INSERT') AND (sale_cdc.tb_client_cdc.saleclient_code <> NEW.client_code)) THEN 

我尝试使用 "sale_cdc.tb_client_cdc.saleclient_code" 而不是 sale_cdc.tb_client_cdc.saleclient_code ,但这并没有解决我的问题。

  • 表格
CREATE TABLE sale.tb_client
(
client_code          CHAR(5) NOT NULL ,
client_name          CHARACTER VARYING(40) NOT NULL ,
address              CHARACTER VARYING(140) ,
city                 CHARACTER VARYING(25)  ,
country              CHARACTER VARYING(60) NOT NULL ,
contact_email        CHARACTER VARYING(100) ,
phone                CHARACTER VARYING(15) ,
parent_client_code   CHAR(5) ,
created_by_user      CHARACTER VARYING(10) NOT NULL DEFAULT 'OS_SYSTEM',
created_date         DATE ,
updated_date         DATE ,
CONSTRAINT pk_client PRIMARY KEY (client_code) ,
CONSTRAINT fk_client_parent FOREIGN KEY (parent_client_code) 
                   REFERENCES sale.tb_client (client_code)
);

CREATE TABLE sale_cdc.tb_client_cdc
(
client_code          CHAR(5) NOT NULL ,
client_name          CHARACTER VARYING(40) NOT NULL ,
address              CHARACTER VARYING(120) ,
city                 CHARACTER VARYING(25)  ,
country              CHARACTER VARYING(50) NOT NULL ,
contact_email        CHARACTER VARYING(100) ,
phone                CHARACTER VARYING(15) ,
parent_client_code   CHAR(5) ,
created_by_user      CHARACTER VARYING(10) NOT NULL DEFAULT 'OS_SYSTEM',
created_date         DATE ,
updated_date         DATE ,
operation            CHAR(1) NOT NULL ,
user_id              CHARACTER VARYING(10) NOT NULL ,
operation_timestamp  TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL , --timestamp [ (p) ] [ without time zone ]
CONSTRAINT pk_client PRIMARY KEY (client_code) ,
CONSTRAINT fk_client_parent FOREIGN KEY (parent_client_code) 
               REFERENCES sale_cdc.tb_client_cdc (client_code)
);

  • 功能
CREATE OR REPLACE FUNCTION update_tb_client_cdc() RETURNS TRIGGER AS 
$$
    BEGIN
        IF ((TG_OP = 'INSERT') AND (sale_cdc.tb_client_cdc.saleclient_code <> NEW.client_code)) THEN
            INSERT INTO sale_cdc.tb_client_cdc VALUES(NEW.*, 'I', user, now());
            RETURN NEW;
        END IF;

    ELSIF ((TG_OP = 'INSERT') AND (sale_cdc.tb_client_cdc.client_code = NEW.client_code)) THEN
            UPDATE sale_cdc.tb_client_cdc
                SET client_name = NEW.client_name,
                address = NEW.address,
                city = NEW.city,
                country = NEW.country,
                contact_email = NEW.contact_email,
                phone = NEW.phone,
                parent_client_code = NEW.parent_client_code,
                created_by_user = NEW.created_by_user,
                created_date = NEW.created_date,
                updated_date = NEW.updated_date,
                operation = 'I',
                user_id = user,
                operation_timestamp = now()
            WHERE client_code = NEW.client_code;
        IF NOT FOUND THEN RETURN NULL; 
        END IF; 
            RETURN NEW; 
    END;
$$ LANGUAGE plpgsql;
  • 触发
CREATE TRIGGER tr_client
AFTER INSERT OR UPDATE OR DELETE ON sale.tb_client
    FOR EACH ROW EXECUTE PROCEDURE update_tb_client_cdc();

错误是:

ERROR:  missing an entry for the table «tb_client_cdc» in the clause FROM
LINE 1: SELECT (((TG_OP = 'INSERT') AND (sale_cdc.tb_client_cdc.clie...
                                         ^

或者:

ERROR:  there is no column «sale_cdc.tb_client_cdc.client_code»
LINE 1: SELECT (((TG_OP = 'INSERT') AND ("sale_cdc.tb_client_cdc.cli...
                                         ^

【问题讨论】:

  • 如果您想在插入tb_client 时将其插入tb_client_cdc 表中怎么会不存在?此外,tb_client_cdc 上的主键毫无意义,每个客户端只能有一行,我假设您希望此表成为某种操作日志。

标签: sql postgresql function stored-procedures triggers


【解决方案1】:

声明一个包含client_code的变量,并检查它是否存在于开头的tb_client_cdc中,如下所示:

CREATE OR REPLACE FUNCTION update_tb_client_cdc() RETURNS TRIGGER AS
$$
DECLARE
    p_client_code tb_client.client_code%TYPE;
BEGIN
    SELECT client_code FROM tb_client_cdc WHERE client_code = NEW.client_code
    INTO p_client_code;


    IF TG_OP = 'INSERT' AND p_client_code IS NULL THEN
        INSERT INTO tb_client_cdc VALUES(NEW.*, 'I', user, now());
        RETURN NEW;
    ELSEIF TG_OP = 'INSERT' AND p_client_code IS NOT NULL THEN
       UPDATE tb_client_cdc
                SET client_name = NEW.client_name,
                address = NEW.address,
                city = NEW.city,
                country = NEW.country,
                contact_email = NEW.contact_email,
                phone = NEW.phone,
                parent_client_code = NEW.parent_client_code,
                created_by_user = NEW.created_by_user,
                created_date = NEW.created_date,
                updated_date = NEW.updated_date,
                operation = 'I',
                user_id = user,
                operation_timestamp = now()
            WHERE client_code = NEW.client_code;

    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

【讨论】:

  • 谢谢@MarcinJ !!!!
  • 对,我没有在我的数据库上创建模式,只是直接使用了public,抱歉。很高兴我能帮上忙!
  • 有人可以解释一下我是否可以在 postgreSQL 中使用运算符“:=”来完成相同的操作?如果答案是肯定的,你能告诉我怎么做吗?
猜你喜欢
  • 2011-05-02
  • 2021-04-10
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
  • 1970-01-01
相关资源
最近更新 更多