1

我在 Firebird SQL 中有以下存储过程:

ALTER PROCEDURE SP_REPORT_USD
(
  PER SMALLINT
)
RETURNS
(
  ACCOUNT_NUMBER CHAR(21),
  AMOUNT NUMERIC(15, 4)
  )

AS

BEGIN

SELECT
      L.ACCOUNT_NUMBER, SUM(CURRROUND(L.DEBIT,2)-CURRROUND(L.CREDIT,2))
   FROM
      LEDGER L
   WHERE
      L.LEDGER_ACCOUNT = '31621' AND L.PERIOD = :PER
   GROUP BY
      L.ACCOUNT_NUMBER

   INTO
      ACCOUNT_NUMBER, AMOUNT;

SUSPEND;

END

当我运行以下查询时:

SELECT * FROM SP_REPORT_USD('17')

我收到以下错误:

程序“ SP_REPORT_USD
”行中的单选中的多行:15,COL:1

第 15 行第 1 行是我的 select 语句在执行存储过程时开始的地方。

我确实测试了以下查询:

SELECT
   L.ACCOUNT_NUMBER, INV.DESCRIPTION, SUM(-(CURRROUND(L.DEBIT,2) - CURRROUND(L.CREDIT,2)))
FROM
   LEDGER L join INVENTORY INV ON L.ACCOUNT_NUMBER = INV.STOCK_CODE
WHERE
   L.LEDGER_ACCOUNT = '31621' AND L.PERIOD = 17
GROUP BY
   L.ACCOUNT_NUMBER, INV.DESCRIPTION

结果符合预期。所以我知道我的查询逻辑是正确的,我只是对存储过程做错了。

任何帮助将不胜感激。

4

1 回答 1

4

问题在于,在存储过程中,SELECT语句仅用于从单行中选择值(所谓的单例选择)。您的查询产生多行,因此出现错误"multiple rows in singleton select"

如果要产生多行,则需要使用FOR SELECT语句,并且SUSPEND语句必须在该FOR SELECT语句的主体中:

ALTER PROCEDURE SP_REPORT_USD(PER SMALLINT)
  RETURNS (ACCOUNT_NUMBER CHAR(21), AMOUNT NUMERIC(15, 4))
AS
BEGIN
   FOR 
     SELECT L.ACCOUNT_NUMBER, SUM(CURRROUND(L.DEBIT,2)-CURRROUND(L.CREDIT,2))
     FROM LEDGER L
     WHERE L.LEDGER_ACCOUNT = '31621' AND L.PERIOD = :PER
     GROUP BY L.ACCOUNT_NUMBER
     INTO :ACCOUNT_NUMBER, :AMOUNT 
   DO
   BEGIN
     SUSPEND;
   END
END

在这种情况下, BEGIN...END周围SUSPEND;是可选的(因为它是单个语句),但我更喜欢始终包含它们。

于 2019-11-24T11:36:20.793 回答