Sql 如何将值的数组参数输入Firebird存储过程?

Sql 如何将值的数组参数输入Firebird存储过程?,sql,arrays,parameters,firebird,Sql,Arrays,Parameters,Firebird,我想向Firebird存储过程输入ID的数组参数 :INPUT_LIST_ID=[1,2,12,45,75,45] 我需要执行以下SQL命令: SELECT * FROM CITY WHERE ID_CITY IN (:INPUT_LIST_ID) 可能吗? 谢谢 不,那是不可能的。虽然Firebird确实有数组数据类型,但对它的支持是基本的,通常不建议使用数组。我认为最简单的解决方案是将数组作为(逗号分隔的)字符串传递,然后使用该语句获取结果集,如 create procedure CITY

我想向Firebird存储过程输入ID的数组参数

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

我需要执行以下SQL命令:

SELECT *
FROM CITY
WHERE ID_CITY IN (:INPUT_LIST_ID)
可能吗?
谢谢

不,那是不可能的。虽然Firebird确实有数组数据类型,但对它的支持是基本的,通常不建议使用数组。我认为最简单的解决方案是将数组作为(逗号分隔的)字符串传递,然后使用该语句获取结果集,如

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
但是,这意味着用于获取结果的语句也会更改,而不是使用存储过程的参数
CITY

SELECT * FROM CITY('1, 2, 12, 45, 75, 45')
发送参数列表的另一个选项是使用。这有专业的,你可以发送大量的ID,而不超过允许的最大语句大小,但它是更多的工作来设置调用

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 ID_CITY IN (SELECT ID FROM GetIntegerList('1, 2, 12, 45, 75, 45'))
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
您必须创建一个名为“GetIntegerList”的新Firebird过程,该过程如下所示:

SELECT *
FROM CITY
WHERE ID_CITY IN (SELECT ID FROM GetIntegerList('1, 2, 12, 45, 75, 45'))
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中完成的。

尝试以下操作:

    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

我认为这是可行的,但我的数据库中有超过10000个城市。@dataol你想全部通过吗?为什么不直接加入包含这些城市的表?@markrotterveel不是全部,只是选定的记录。但用户可以选择1个或10个城市。@ DATAOL考虑使用A,插入选定的城市,加入反对。@ MrkRoTovielOK。我试试看。谢谢很好,谢谢你!但是它只适用于短字符串(比如50个字符),而在长字符串上崩溃=((在这种情况下,你能帮我吗?很抱歉,但幸运的是,我不再使用firebird了,但是不管字符串长度如何,它都应该工作,你发现了什么问题?