【问题标题】:Syntax error with NEW while creating a trigger in PostgreSQL在 PostgreSQL 中创建触发器时出现 NEW 语法错误
【发布时间】:2013-09-09 14:12:53
【问题描述】:

我正在 Postgresql 中创建一个触发器,如下所示。

    CREATE TRIGGER "PRODUCT_ADD_TRIGGER" AFTER INSERT
   ON product FOR EACH ROW
   EXECUTE PROCEDURE INVENTORY_ENTRY_NEW_PRODUCT(NEW.productcode);
COMMENT ON TRIGGER "PRODUCT_ADD_TRIGGER" ON product
  IS '-- Executes a procedure that inserts a row into the inventorytxns table.';

在pgAdmin-III的查询管理器中执行时,抛出如下错误。

ERROR:  syntax error at or near "."
LINE 3: ... EXECUTE PROCEDURE INVENTORY_ENTRY_NEW_PRODUCT(NEW.productco...
                                                             ^

********** Error **********

ERROR: syntax error at or near "."
SQL state: 42601
Character: 130

谁能告诉我我的代码有什么问题。我到处找。

EDIT:要执行的过程的代码。此过程已成功添加到数据库中。

-- Function: "INVENTORY_ENTRY_NEW_PRODUCT"(integer)

-- DROP FUNCTION "INVENTORY_ENTRY_NEW_PRODUCT"(integer);

CREATE OR REPLACE FUNCTION "INVENTORY_ENTRY_NEW_PRODUCT"(productcode integer)
  RETURNS record AS
$BODY$
-- Declare the required variables.
DECLARE
    -- Inventory row that stores the result of the query on the inventory table.
    inventoryrow inventory%ROWTYPE;
    result record;
BEGIN

    SELECT * INTO inventoryrow from inventory where fk_productcode = productcode;

    IF NOT FOUND THEN
        -- INVENTORY TRANSACTION CAN BE ADDED.
        -- An inventory transaction can be added to the inventorytxns table
        INSERT INTO inventorytxns (fk_productcode,fk_txntypeid) VALUES(productcode,6);

        -- Once a row is added into the inventory txns table, it automatically adds data into the inventory table.
        SELECT * INTO result FROM INVENTORY WHERE fk_productcode = productcode;

        IF NOT FOUND THEN
            -- RAISE AN EXCEPTION. THIS OPERATION IS SUPPOSED TO HAPPEN.
            RAISE EXCEPTION 'Product with product code % added in inventorytxns table but not added in inventory table',productcode;
        END IF;
        -- Transaction type 6 represents addition of a new product transaction type.
    END IF;

    RAISE DEBUG 'Product with product code % already available in inventory',productcode;

END;
-- Check if the inventory entry already exits in the inventory table.
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION "INVENTORY_ENTRY_NEW_PRODUCT"(integer)
  OWNER TO postgres;
COMMENT ON FUNCTION "INVENTORY_ENTRY_NEW_PRODUCT"(integer) IS 'Adds a new entry in the inventorytxns table for a new product.';

【问题讨论】:

    标签: sql postgresql triggers


    【解决方案1】:

    您应该在official docs 中阅读有关触发过程的更多信息。当你调用触发函数OLD、NEW等一堆东西或通过TG_NARGS和TG_ARGV隐式传递时,你不应该自己做。

    CREATE OR REPLACE FUNCTION INVENTORY_ENTRY_NEW_PRODUCT()
    RETURNS TRIGGER AS $INVENTORY_ENTRY_NEW_PRODUCT_TRIGGER$
    BEGIN
      -- Here you can access NEW.productcode
    
    RETURN NULL;
    END;
     $INVENTORY_ENTRY_NEW_PRODUCT_TRIGGER$ LANGUAGE plpgsql;
    
    
    CREATE TRIGGER PRODUCT_ADD_TRIGGER AFTER INSERT
    ON product FOR EACH ROW
    EXECUTE PROCEDURE INVENTORY_ENTRY_NEW_PRODUCT();
    

    更新

    因此,在您的情况下,触发器应如下所示,触发器功能应如下所示:

    CREATE OR REPLACE FUNCTION "INVENTORY_ENTRY_NEW_PRODUCT"()
      RETURNS record AS
    $BODY$
    -- Declare the required variables.
    DECLARE
        -- Inventory row that stores the result of the query on the inventory table.
        inventoryrow inventory%ROWTYPE;
        result record;
    BEGIN
    
        SELECT * INTO inventoryrow from inventory where fk_productcode = NEW.productcode;
    
        IF NOT FOUND THEN
            -- INVENTORY TRANSACTION CAN BE ADDED.
            -- An inventory transaction can be added to the inventorytxns table
            INSERT INTO inventorytxns (fk_productcode,fk_txntypeid) VALUES(NEW.productcode,6);
    
            -- Once a row is added into the inventory txns table, it automatically adds data into the inventory table.
            SELECT * INTO result FROM INVENTORY WHERE fk_productcode = NEW.productcode;
    
            IF NOT FOUND THEN
                -- RAISE AN EXCEPTION. THIS OPERATION IS SUPPOSED TO HAPPEN.
                RAISE EXCEPTION 'Product with product code % added in inventorytxns table but not added in inventory table',NEW.productcode;
            END IF;
            -- Transaction type 6 represents addition of a new product transaction type.
        END IF;
    
        RAISE DEBUG 'Product with product code % already available in inventory',productcode;
    
    END;
    -- Check if the inventory entry already exits in the inventory table.
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    

    来自文档

    当一个 PL/pgSQL 函数作为触发器调用时,会在顶层块中自动创建几个特殊变量。它们是:

    数据类型记录;为行级触发器中的 INSERT/UPDATE 操作保存新数据库行的变量。此变量在语句级触发器和 DELETE 操作中为 NULL。

    数据类型记录;保存旧数据库行的变量,用于行级触发器中的 UPDATE/DELETE 操作。此变量在语句级触发器和 INSERT 操作中为 NULL。

    ...

    总结

    您应该记住,触发器函数与“普通”PostgreSQL 函数确实不同,它只能由提供适当上下文的触发器调用。另一方面,新。老的。和其他与触发器相关的东西在触发器执行上下文之外完全没有意义。

    【讨论】:

    • 忘了说。我已经定义了程序。我已经更新了我的问题中的代码。
    • 我的意思是你不应该通过 args 来触发函数 this。它们可通过 TG_NARGS 和 TG_ARGV 在触发函数中使用。
    • 您能详细说明一下吗?你有什么例子吗?
    • 太棒了。但是,我希望我的代码易于阅读。这就是我将产品代码作为参数传递的原因。在您的功能中,尚不清楚 NEW 来自何处。我想从新记录中提取产品代码并将其发送到另一个函数。这将使我的代码易于理解和维护。你知道有什么方法可以实现吗?
    • 其实很清楚,如果你还记得trigger函数真的和普通函数不同,它只能被trigger调用,它为函数提供了适当的上下文。另一方面,新。老的。和其他与触发器相关的东西在触发器执行上下文之外完全没有意义。为了清楚起见,我建议使用 cleat 命名约定,例如 foo_fn 用于正常功能,而 foo_trg_fn 用于触发功能。
    猜你喜欢
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2012-10-20
    • 2015-10-01
    • 1970-01-01
    相关资源
    最近更新 更多