Firebird SQL 在存储过程中按名称访问参数
Firebird SQL access parameter by name in stored procedure
有没有办法在 Firebird (v1.5) 存储过程中按名称访问输出参数?结果字段应该是指定年份的月份,如果我不必将代码复制 12 次会更容易。
下面是一个例子(最终代码比这个更复杂):
SET TERM !!;
CREATE PROCEDURE MY_PROC (
I_PARAM INTEGER)
RETURNS (
O_PARAM_1 INTEGER, O_PARAM_2 INTEGER, O_PARAM_3 INTEGER, O_PARAM_4 INTEGER,
O_PARAM_5 INTEGER, O_PARAM_6 INTEGER, O_PARAM_7 INTEGER, O_PARAM_8 INTEGER,
O_PARAM_9 INTEGER, O_PARAM_10 INTEGER, O_PARAM_11 INTEGER, O_PARAM_12 INTEGER)
AS
declare MONTH_ID INTEGER;
BEGIN
MONTH_ID = 1;
while (MONTH_ID <= 12) do
begin
select
count(*)
from
MY_TABLE M
where
M.MONTH_ID = I
into
>>>> :O_PARAM_???; -- need access by name
MONTH_ID = MONTH_ID + 1;
end
suspend;
END!!
SET TERM ;!!
这是不可能的。 Firebird 需要在编译时知道它将使用哪个变量。无法动态引用输出参数。
作为中间解决方案,您可以将结果赋值给一个临时变量,然后只赋值给 if-else
长链中的正确变量。它仍然是代码重复,但比一遍又一遍地重复查询要少。
您还可以执行一个查询,一次性生成所有月份的结果。这会导致轻微的代码膨胀,但可能更有效:
select
(SELECT count(*) from MY_TABLE where MONTH_ID = 1),
(SELECT count(*) from MY_TABLE where MONTH_ID = 2),
(SELECT count(*) from MY_TABLE where MONTH_ID = 3),
-- ...and so on
into :O_PARAM_1, :O_PARAM_2, :O_PARAM_3;
如果您使用更新的 Firebird 版本,如 Firebird 2.5,您可以使用 CTE(尽管对于这个简单的查询,它并没有简化很多):
WITH counts AS (SELECT MONTH_ID, count(*) AS MONTH_COUNT from MY_TABLE M GROUP BY MONTH_ID)
select
(SELECT MONTH_COUNT from counts where MONTH_ID = 1),
(SELECT MONTH_COUNT from counts where MONTH_ID = 2),
(SELECT MONTH_COUNT from counts where MONTH_ID = 3),
-- ...and so on
into :O_PARAM_1, :O_PARAM_2, :O_PARAM_3;
一个完全不同的解决方案是放弃可执行存储过程的想法(尽管在您当前的解决方案中存在 SUSPEND
它实际上总是可选择一行),而是使用一个可选择的returns 结果作为行的过程。这是否是解决方案取决于您的实际数据需求。
CREATE PROCEDURE MY_PROC (
I_PARAM INTEGER)
RETURNS (
MONTH_ID INTEGER, MONTH_COUNT INTEGER)
AS
BEGIN
FOR
select MONTH_ID, count(*)
from MY_TABLE M
GROUP BY MONTH_ID
into :MONTH_ID, :MONTH_COUNT
BEGIN
SUSPEND;
END
END
有没有办法在 Firebird (v1.5) 存储过程中按名称访问输出参数?结果字段应该是指定年份的月份,如果我不必将代码复制 12 次会更容易。
下面是一个例子(最终代码比这个更复杂):
SET TERM !!;
CREATE PROCEDURE MY_PROC (
I_PARAM INTEGER)
RETURNS (
O_PARAM_1 INTEGER, O_PARAM_2 INTEGER, O_PARAM_3 INTEGER, O_PARAM_4 INTEGER,
O_PARAM_5 INTEGER, O_PARAM_6 INTEGER, O_PARAM_7 INTEGER, O_PARAM_8 INTEGER,
O_PARAM_9 INTEGER, O_PARAM_10 INTEGER, O_PARAM_11 INTEGER, O_PARAM_12 INTEGER)
AS
declare MONTH_ID INTEGER;
BEGIN
MONTH_ID = 1;
while (MONTH_ID <= 12) do
begin
select
count(*)
from
MY_TABLE M
where
M.MONTH_ID = I
into
>>>> :O_PARAM_???; -- need access by name
MONTH_ID = MONTH_ID + 1;
end
suspend;
END!!
SET TERM ;!!
这是不可能的。 Firebird 需要在编译时知道它将使用哪个变量。无法动态引用输出参数。
作为中间解决方案,您可以将结果赋值给一个临时变量,然后只赋值给 if-else
长链中的正确变量。它仍然是代码重复,但比一遍又一遍地重复查询要少。
您还可以执行一个查询,一次性生成所有月份的结果。这会导致轻微的代码膨胀,但可能更有效:
select
(SELECT count(*) from MY_TABLE where MONTH_ID = 1),
(SELECT count(*) from MY_TABLE where MONTH_ID = 2),
(SELECT count(*) from MY_TABLE where MONTH_ID = 3),
-- ...and so on
into :O_PARAM_1, :O_PARAM_2, :O_PARAM_3;
如果您使用更新的 Firebird 版本,如 Firebird 2.5,您可以使用 CTE(尽管对于这个简单的查询,它并没有简化很多):
WITH counts AS (SELECT MONTH_ID, count(*) AS MONTH_COUNT from MY_TABLE M GROUP BY MONTH_ID)
select
(SELECT MONTH_COUNT from counts where MONTH_ID = 1),
(SELECT MONTH_COUNT from counts where MONTH_ID = 2),
(SELECT MONTH_COUNT from counts where MONTH_ID = 3),
-- ...and so on
into :O_PARAM_1, :O_PARAM_2, :O_PARAM_3;
一个完全不同的解决方案是放弃可执行存储过程的想法(尽管在您当前的解决方案中存在 SUSPEND
它实际上总是可选择一行),而是使用一个可选择的returns 结果作为行的过程。这是否是解决方案取决于您的实际数据需求。
CREATE PROCEDURE MY_PROC (
I_PARAM INTEGER)
RETURNS (
MONTH_ID INTEGER, MONTH_COUNT INTEGER)
AS
BEGIN
FOR
select MONTH_ID, count(*)
from MY_TABLE M
GROUP BY MONTH_ID
into :MONTH_ID, :MONTH_COUNT
BEGIN
SUSPEND;
END
END