Параметр доступа к SQL Firebird по имени в хранимой процедуре

Есть ли способ получить доступ к выходному параметру по имени в хранимой процедуре 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 ;!!

person tcxbalage    schedule 03.05.2015    source источник


Ответы (1)


Это невозможно. 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 в вашем текущем решении она фактически выбирается всегда с одной строкой) и вместо этого использовать выбираемую процедуру, которая возвращает результат в виде строк. Если это решение, зависит от ваших реальных потребностей в данных.

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
person Mark Rotteveel    schedule 04.05.2015