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

Sql 为什么此存储过程返回一个空集?,sql,stored-procedures,firebird,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 firs

我试图构建一个存储过程来封装一些复杂的逻辑。以下是一些匿名的基本代码:

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中运行它,它会给出预期的结果。但是如果我说
使用相同的参数从GET_DATA(1,1,2,3)中选择ID,NAME
,我会得到一个空的结果集


所以在存储过程级别出现了一些问题。有人知道它是什么以及我如何修复它吗?

您将其视为一个可选择的过程,但Firebird并不认为这是一个可选择的过程,而是一个可执行的过程。如果在最后添加一个
SUSPEND
,它会成功的,而且这会解决您的问题。

SUSPEND
就像一个反向的
FETCH
它的意思是“作为结果发送一行”

如果您添加了4行挂起;select*from GET_数据(参数)的结果应至少为四行空值。这意味着您的select语句没有返回任何行,或者有一行返回空值

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


选择1,'TEST'从RDB$数据库进入:ID,:NAME

您的过程始终返回1个结果,即使select返回1或0个结果,因为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 ; ^

LOOKUP\u table 2.VALUE
是否为可空字段?因为如果
的结果集包含
NULL
,则
不在()
中永远不可能为真。(如果这是问题所在,那么修复方法是将
和VALUE not null
添加到子查询。)@ruakh:No,两个查找表都没有null约束。就像我说的,这个查询在逻辑上是正确的;当我将其作为存储过程运行时,它只是没有运行任何结果。@如果您为这些表和一些示例数据发布DDL statemenst,这样我们就可以重新创建它,Mason会很高兴的-SP似乎可以,您是否尝试在或中调试它?这可能是转换问题吗?例:QO表的X、Y和W列是否也定义为
INTEGER
?您是否在SP中将变量更改为值,而不是在Firebird Maestro上尝试右选择?没有。我试过了,但没用。我会更新这个问题。表示
挂起
实际上应该在
选择
?@ruakh
挂起
之前“打印”返回变量,然后在选择它们之前empty@ruakh不,如果仔细观察,第一次挂起将返回在循环外部初始化的值。@MarkRotterVeel:有趣的一点。我猜那个页面的作者只是被搞糊涂了。要么1个结果要么0个结果——很好:)但我并不总是得到1个结果;运行此查询时,我总是得到一个空集(0个结果)。像那样把它变成for循环也没用。