我想执行更新前触发器,该触发器检查行中的所有字段是否相同并取消更新。我正在使用Firebird 2.5。
我目前的做法是这样的:
-
使用过程获取带有
old.FIELD
、new.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 ; ^
效果很好! 谢谢,马克!