为什么这个存储过程返回一个空集?

时间:2012-03-26 17:49:47

标签: sql stored-procedures firebird

我正在尝试构建一个存储过程来封装一些复杂的逻辑。这是基本代码,稍微匿名:

SET TERM ^ ;

RECREATE PROCEDURE GET_DATA (
 USERID   INTEGER,
 W        INTEGER,
 X        INTEGER,
 Y        INTEGER)
RETURNS (
 ID       INTEGER,
 NAME     VARCHAR(64) CHARACTER SET UTF8)
AS 
BEGIN
  select first 1
    QP.ID,
    QO.NAME
  from QP
  join QO
    on QO.ID = QP.QO_ID
  where
    (QO.W = :w) and (QO.X = :x) and (QO.Y = :y)
    and ((QP.PREREQUISITE in (
      select VALUE
      from LOOKUP_TABLE1
      where USER_ID = :userid))
      or (QP.PREREQUISITE is null))
    and (QO.Q_ID not in (
      select VALUE
      from LOOKUP_TABLE2
      where USER_ID = :userid))
  order by QP.SEQUENCE desc
  into :ID, :NAME;
  suspend;
END^

SET TERM ; ^

预计会返回1或0个结果。这在逻辑上是正确的;如果我接受SELECT查询,手动替换参数,并在Firebird Maestro中运行它,它会给出预期的结果。但是如果我说select ID, NAME from GET_DATA(1, 1, 2, 3),使用相同的参数,我会得到一个空的结果集。

因此存储过程级别出现问题。任何人都知道它是什么以及如何解决它?

3 个答案:

答案 0 :(得分:2)

即使选择返回1或0结果,您的程序也始终返回1结果,因为SUSPEND与选择无关。

要获得0或1以选择相应的结果,您可以使用:

RECREATE PROCEDURE GET_DATA (
   USERID   INTEGER,
   W        INTEGER,
   X        INTEGER,
   Y        INTEGER)
  RETURNS (
   ID       INTEGER,
   NAME     VARCHAR(64) CHARACTER SET UTF8)
  AS
  BEGIN
    FOR select first 1
      QP.ID,
      QO.NAME
    from QP
    join QO
      on QO.ID = QP.QO_ID
    where
      (QO.W = :w) and (QO.X = :x) and (QO.Y = :y)
      and ((QP.PREREQUISITE in (
        select VALUE
        from LOOKUP_TABLE1
        where USER_ID = :userid))
        or (QP.PREREQUISITE is null))
      and (QO.Q_ID not in (
        select VALUE
        from LOOKUP_TABLE2
        where USER_ID = :userid))
    order by QP.SEQUENCE desc
    into :ID, :NAME DO
       suspend;
  END^

  SET TERM ; ^

答案 1 :(得分:0)

您将此视为可选择的过程,但Firebird并未将此视为可选过程,而是将其视为可执行过程。如果你在最后添加SUSPEND,那么AFAIK应该可以解决你的问题。

答案 2 :(得分:0)

SUSPEND就像倒置的FETCH,意思是“发送一行作为结果”。

如果使用SUSPEND添加4行; select * from GET_DATA(参数)的结果应至少为四行,且值为null。这意味着您的select语句没有返回任何行,或者一行返回空值。

使用更简单的查询进行一些测试。

select 1, 'TEST' from RDB$DATABASE into :ID, :NAME;