Firebird 在触发器内执行过程和语句(该过程的结果作为其中的一部分)
Firebird execute procedure and statement (with result from that procedure as part of it) inside trigger
我想执行更新前触发器,检查一行中的所有字段是否相同并取消更新。我正在使用 Firebird 2.5。
我目前的做法是这样的:
使用过程获取带有old.FIELD
、new.FIELD
的所有字段名称。像这样:
IF (new.LOCATION IS DISTINCT FROM
old.LOCATION) OR (new.NAME IS DISTINCT FROM old.NAME)
... return 类型的过程是 Varchar(1000)
。这行得通。程序是这样的:STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE');
- 如果此条件为真,我想将一些值插入
SYNC_INFO
table 并继续更新该行。如果条件为假,我想取消更新行。我通过抛出异常来做到这一点。
我的代码:
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 ; ^
当我尝试执行此操作时,出现以下错误:
Token unknown - line 18, column 10
execute
这是这行代码:
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
cannot be used to execute snippets of PSQL (procedural SQL) like that, it can only execute normal DSQL (dynamic SQL), and you cannot access the context variables (like new
) in that way. You would need to pass the required columns from new
explicitly as parameter values to execute statement
, and you could try if you can get it to work by wrapping the PSQL you try to execute dynamically in an 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 ; ^
干得漂亮!谢谢,马克!
我想执行更新前触发器,检查一行中的所有字段是否相同并取消更新。我正在使用 Firebird 2.5。
我目前的做法是这样的:
使用过程获取带有
old.FIELD
、new.FIELD
的所有字段名称。像这样:IF (new.LOCATION IS DISTINCT FROM old.LOCATION) OR (new.NAME IS DISTINCT FROM old.NAME)
... return 类型的过程是
Varchar(1000)
。这行得通。程序是这样的:STRING_SESTAVLJEN_ENAKOST_TABEL('MERILA_STRANKE');
- 如果此条件为真,我想将一些值插入
SYNC_INFO
table 并继续更新该行。如果条件为假,我想取消更新行。我通过抛出异常来做到这一点。
我的代码:
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 ; ^
当我尝试执行此操作时,出现以下错误:
Token unknown - line 18, column 10
execute
这是这行代码:
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
cannot be used to execute snippets of PSQL (procedural SQL) like that, it can only execute normal DSQL (dynamic SQL), and you cannot access the context variables (like new
) in that way. You would need to pass the required columns from new
explicitly as parameter values to execute statement
, and you could try if you can get it to work by wrapping the PSQL you try to execute dynamically in an 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 ; ^
干得漂亮!谢谢,马克!