Firebird 在触发器内执行过程和语句(该过程的结果作为其中的一部分)



我想执行更新前触发器,该触发器检查行中的所有字段是否相同并取消更新。我正在使用Firebird 2.5。

我目前的做法是这样的:

  • 使用过程获取带有old.FIELDnew.FIELD的所有字段名称。像这样:

    IF (new.LOCATION IS DISTINCT FROM
    old.LOCATION) OR (new.NAME IS DISTINCT FROM old.NAME)
    

    。过程的返回类型为Varchar(1000)。这行得通。程序是这样的:STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE');

  • 如果此条件为真,我想在表中插入一些值SYNC_INFO并继续更新行。如果条件为假,我想取消更新行。我通过抛出一个例外来做到这一点。

我的代码:

SET TERM ^ ;
ALTER TRIGGER BI_MERILA_STRANKE ACTIVE
BEFORE INSERT OR UPDATE POSITION 0
AS 
declare variable besedilo_primerjave varchar(5000);
BEGIN 
begin
if (new.ID_MERILA_STRANKE is null OR new.ID_MERILA_STRANKE = 0) then new.ID_MERILA_STRANKE = gen_id(GEN_ID_MERILA_STRANKE,1);
end
begin    
besedilo_primerjave = execute procedure 
STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE');   -- if this is true then you need to save othervise not
execute statement besedilo_primerjave || ' THEN BEGIN INSERT INTO SYNC_INFO(TABLE_NAME,ID_COLUMN_NAME,ID_VALUE,DATETIME) 
VALUES (
''MERILA_STRANKE'',
''ID_MERILA_STRANKE'',
NEW.ID_MERILA_STRANKE,
CURRENT_TIMESTAMP
);
END ELSE BEGIN
exception ENAK_RECORD;
END';
end
END^
SET TERM ; ^

当我尝试执行此操作时,出现以下错误:

令牌未知 - 第 18 行,第 10
列执行

这是这行代码:

execute statement besedilo_primerjave || ' THEN BEGIN INSERT INTO SYNC_INFO(TABLE_NAME,ID_COLUMN_NAME,ID_VALUE,DATETIME)

我与Firebird合作不多,所以如果有人知道我做错了什么,或者如果有人知道实现这一目标的更好解决方案,请帮助我。

我需要在数据库上做,可能更好的方法是在软件中做,但我不能那样做。

你对有问题的行是错误的。实际问题在

besedilo_primerjave = execute procedure STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE'); 

分配后不能有execute procedure,您需要使用

execute procedure STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE')
returning_values :besedilo_primerjave;

您的下一条语句不能工作,因为execute statement不能用于执行 PSQL(过程 SQL)的代码片段,它只能执行普通的 DSQL(动态 SQL),并且您不能以这种方式访问上下文变量(如new)。您需要将所需的列从new显式地作为参数值传递给execute statement,您可以尝试通过将您尝试动态执行的 PSQL 包装在execute block中来让它工作,但这会很快变得丑陋。

我建议你重新考虑你正在做的事情,也许在触发器中编写真正的逻辑,而不是像你现在试图做的那样完全动态地做它。

这是我基于上面 Mark 的示例并在 Firebird 3.0 中工作的示例:

SET TERM ^ ;
CREATE TRIGGER UMCDB_DRIVER_BI FOR UMCDB_DRIVER ACTIVE
BEFORE INSERT POSITION 0
AS 
BEGIN 
new.ID = gen_id(GEN_DRIVER, 1);
new.CREATE_USERID = CURRENT_USER;
new.CREATE_TS = CURRENT_TIMESTAMP;
-- Get the hashed value for the driver name.
execute procedure PRC_NAME_HASH( new.DRVR_FIRST_NAME, new.DRVR_MID_INITS, new.DRVR_LAST_NAME)
returning_values new.NAME_HASH;
END^
SET TERM ; ^

效果很好! 谢谢,马克!

最新更新