在外部数据库上更新时存储过程中出现令牌未知错误

Token unkown error in stored procedure when updating on external database

create or alter procedure UPDATECAS (
VNEWSTOCK double precision,
as
declare variable LCCOMANDO2 varchar(256);
begin
  LCCOMANDO2 = 'update CAS
          set STOCK = STOCK-' || :VNEWSTOCK || '';

  for execute statement LCCOMANDO2 on external 'C:\DB\DB.GDB' as
  user 'SYSDBA' password 'masterkey'
  suspend;
end

我正在使用 Firebird,我想创建一个存储过程来在另一个数据库中进行更新,但我不明白我遗漏了什么,因为在编译时出现以下错误:

can't format message 13:896 -- message file C:\WINDOWS\firebird.msg not found.
Dynamic SQL Error.
SQL error code = -104.
Token unknown.
suspend

错误代码 13:896 通常显示为错误代码 336397184,转换为消息“无效令牌”。 (顺便说一句:“无法格式化消息” 错误表明您正在使用无法找到 firebird.msg 文件的 fbclient.dll有错误消息,或者您使用的是不包含特定消息的旧版本)

在这种特定情况下,问题是您犯了一个语法错误:您的语句缺少单词 DO,如 Firebird 2.5 语言参考中的 FOR EXECUTE STATEMENT 所示。结果,Firebird 解析器在它不期望的位置找到 SUSPEND(它期望 DO,或 FOR EXECUTE STATEMENT 语法中的另一个标记)。 - 明显但不正确的 - 修复是:

for execute statement LCCOMANDO2 on external 'C:\DB\DB.GDB' as
  user 'SYSDBA' password 'masterkey' do
begin
  suspend;
end

注意:在 begin ... end 中包含 suspend; 不是必需的,但我认为它提高了可读性。

这会解决眼前的问题,但会导致另一个错误,因为 FOR EXECUTE STATEMENT 旨在执行产生结果集的语句,而 UPDATE 不会产生结果集.

相反,您需要使用 EXECUTE STATEMENT 而没有 FOR。我还强烈建议您适当地参数化更新语句,而不是将值连接到查询字符串中。鉴于您的存储过程不产生任何数据(它没有 RETURNS 子句),使用 SUSPEND 子句也不合适。

最终代码应该是这样的:

create or alter procedure UPDATECAS (VNEWSTOCK double precision)
as
begin
  execute statement ('update CAS set STOCK = STOCK - :newstock') (newstock = VNEWSTOCK) 
    on external 'C:\DB\DB.GDB' as user 'SYSDBA' password 'masterkey';
end

不过请注意,对库存商品使用双精度似乎并不合适。通常股票是离散单位,所以 INTEGERBIGINT 会更合适,或者如果你需要小数值,DECIMAL(或 NUMERIC)的准确性可能比DOUBLE PRECISION.

的不精确性