8

我在 Firebird 中有一个大型查询(我使用 FlameRobin 运行),在所有地方都使用了一个参数,但是让下面的查询运行就可以了:

SELECT * FROM customers WHERE customerid = 1234;

我想将其定义1234为一个变量,例如customerID,以便我可以轻松地将其替换为其他内容。

我知道我需要把它放在一个EXECUTE BLOCK.

EXECUTE BLOCK 
AS
DECLARE customerID INT = 1234;

BEGIN
  SELECT * FROM customers WHERE customerid = :customerID
END

如果有任何重要性,我得到的错误是Engine Message : Dynamic SQL Error SQL error code = -104 Unexpected end of command - line 3, column 26

4

2 回答 2

16

问题是 FlameRobin 需要知道一个语句何时结束以及下一个语句何时开始。默认情况下,它;为此使用分号 ( )。然而 anEXECUTE BLOCK本质上是一个不存储在数据库中的存储过程,因此它包含的 PSQL 代码也使用分号作为语句分隔符。

这样做的后果是您会收到语法错误,因为 FlameRobin 正在向服务器发送不完整的语句(即:它在;遇到每个语句后都发送一条语句)。

您需要指示 FlameRobin 使用不同的语句终止符,使用SET TERM. 其他 Firebird 查询工具(例如 isql)也需要这个,但它实际上并不是 Firebird 本身语法的一部分!

所以你需要执行你的代码:

-- Instruct flamerobin to use # as the terminator
SET TERM #;
EXECUTE BLOCK 
AS
DECLARE customerID INT = 1234;

BEGIN
  SELECT * FROM customers WHERE customerid = :customerID;
END#
-- Restore terminator to ;
SET TERM ;#

但是这样做仍然会导致错误,因为此查询对 PSQL 无效:SELECTPSQL 块中的 A 需要一个INTO子句将列映射到变量。并且EXECUTE BLOCK要从返回给 FlameRobin 的值中获取值,您还需要指定一个RETURNS子句,如以下文档中所述EXECUTE BLOCK

-- Instruct flamerobin to use # as the terminator
SET TERM #;
EXECUTE BLOCK 
   RETURNS (col1 INTEGER, col2 VARCHAR(100))
AS
DECLARE customerID INT = 1234;

BEGIN
  SELECT col1, col2 FROM customers WHERE customerid = :customerID INTO :col1, :col2;
  SUSPEND;
END#
-- Restore terminator to ;
SET TERM ;#

据我所知,SUSPEND这里技术上不需要,但如果不包含返回的行,Flamerobin 将不会获取它。

但是,如果选择产生多行,上述方法将不起作用。为此,您需要FOR SELECT ... DO与 a 结合使用SUSPEND

-- Instruct flamerobin to use # as the terminator
SET TERM #;
EXECUTE BLOCK 
   RETURNS (col1 INTEGER, col2 VARCHAR(100))
AS
DECLARE customerID INT = 1234;

BEGIN
  FOR SELECT col1, col2 FROM customers WHERE customerid = :customerID INTO :col1, :col2
  DO
     SUSPEND;
END#
-- Restore terminator to ;
SET TERM ;#

这里SUSPEND返回该行并等待调用者获取该行,然后继续FOR循环。这样它将遍历结果。

恕我直言,这为参数化付出了太多努力。您可能想在使用 FlameRobin 时考虑不进行参数化,或者使用支持为 Firebird 的普通参数占位符询问参数值的工具(但老实说,我不确定是否有任何参数值)。

于 2013-10-10T15:36:51.803 回答
1

那么你需要一个输入和返回值,例如:

EXECUTE BLOCK (p_customerID integer=?)
returns(col_1 type of column table.id_cv)
as
begin
  for
    select col_1 from table
    where customerID=:p_customerID
    into col_1 do
     suspend;
end

Delphi 作为客户端:

myquery1.ParamByName('p_customerID ').Value:=1234;
myquery1.Open()
if not myquery1.IsEmpty then
begin
  // using returning values
  if myquery1.FieldbyName('col_1').AsString='this' then DoThat(); 
end;

在您不需要输入参数和/或返回值时使用这种方式;

于 2021-08-16T13:30:42.873 回答