Как ввести параметр массива значений в хранимую процедуру Firebird?

Я хотел бы ввести параметр массива идентификаторов Хранимая Процедура Firebird.

:INPUT_LIST_ID = [1, 2, 12, 45, 75, 45]

Мне нужно выполнить эту команду SQL:

SELECT *
FROM CITY
WHERE ID_CITY IN (:INPUT_LIST_ID)

это возможно? Спасибо!

4 ответов


вы также можете использовать что-то вроде этого:

SELECT *
FROM CITY
WHERE ID_CITY IN (SELECT ID FROM GetIntegerList('1, 2, 12, 45, 75, 45'))

вам нужно будет создать новую процедуру Firebird под названием "GetIntegerList", которая будет выглядеть примерно так:

CREATE OR ALTER PROCEDURE "GETINTEGERLIST"("AINTEGERLIST" VARCHAR(32000))
returns (
  ID integer
)
as
  declare variable IntegerList varchar(32000);
  declare variable CommaPos integer;
  declare variable IntegerVal varchar(10);
begin
  IntegerList = AIntegerList || ' ';
  CommaPos = Position(',', IntegerList);

  while (CommaPos > 0) do
  begin
    IntegerVal = Trim(SubString(IntegerList from 1 for CommaPos - 1));

    if (Char_Length(IntegerVal) > 0) then
    begin
      if (IntegerVal similar to '[0-9]*') then
      begin
        ID = Cast(IntegerVal as integer);
        suspend;
      end
    end

    if (Char_Length(IntegerList) > CommaPos) then
      IntegerList = SubString(IntegerList from CommaPos + 1);
    else
      IntegerList = '';

    CommaPos = Position(',', IntegerList);
  end

  IntegerList = Trim(IntegerList);

  if (Char_Length(IntegerList) > 0) then
  begin
    if (IntegerList similar to '[0-9]*') then
    begin
      ID = Cast(IntegerList as integer);
      suspend;
    end
  end
end

заметь, это было сделано в Firebird 2.5.2.


AFAIK нет, это невозможно. Хотя Firebird имеет тип данных массива, поддержка его рудиментарна, и использование массивов обычно не рекомендуется. Я думаю, что самым простым решением было бы передать массив как (разделенную запятыми) строку, а затем использовать for execute statement заявление, чтобы получить resultset, что-то вроде

create procedure CITY (INPUT_LIST_ID varchar(1024)) 
returns( ... )
as
begin
  for execute statement
    'select ... from T where ID_CITY IN ('|| INPUT_LIST_ID ||')' into ...
  do begin
     suspend;
  end
end

это означает, однако, что оператор, который вы используете для получения результата, также изменяется вместо WHERE вы бы использовали параметр хранимая процедура CITY:

SELECT * FROM CITY('1, 2, 12, 45, 75, 45')

другой вариант отправки списка параметров-использовать глобальная временная таблица. Это имеет pro, что вы можете отправить огромное количество идентификаторов, не превышая максимально допустимый размер операторов, но это больше работы, чтобы настроить вызов...

create global temporary table SP_CITY_PARAMS (
  id int not null primary key
)
on commit delete rows;

create procedure CITY
returns( ... )
as
begin
  for select ... from T where ID_CITY IN (
      select id from SP_CITY_PARAMS
  ) into ...
  do begin
     suspend;
  end
end

попробуйте это:

    SELECT *
    FROM CITY
    WHERE '/city1/city2/city.../' containing '/' || ID_CITY || '/';

Если вы используете Firebird 1.5 (он должен работать и на более высоких версиях), вы можете использовать эту простую функцию, которую я сделал, чтобы преобразовать одну строку в целочисленный массив:

create or alter procedure INTEGER_LIST (
    input varchar(4096))
returns (
    INT_VALUE integer)
as
declare variable CHAR_COUNT integer;
declare variable PARAM_LENGTH integer;
declare variable READ_VALUE char(1);
declare variable CURRENT_INTEGER varchar(20);
begin
    param_length = strlen(input);
    char_count = 0;
    current_integer = '';
    while (char_count < param_length) do begin
        char_count = :char_count + 1;
        read_value = substr(:input, :char_count, :char_count);
        if (:read_value <> ',') then begin
            current_integer = :current_integer || :read_value;
        end else if (:read_value <> ' ') then  begin
            int_value = cast(:current_integer as integer);
            current_integer = '';
            suspend;
        end

        if (:char_count = :param_length) then begin
            int_value = cast(:current_integer as integer);
            suspend;
        end
    end
end

использование

select int_value from integer_list('1,2,3,4, 5, 200, 1, 598415, 2')

отвечу на это:

INT_VALUE
1
2
3
4
5
200
1
598415
2