如果没有预定义值的数量,如何在单个参数中传递多个值



我在dbgrid中选择一些行,然后必须在存储过程或查询的参数中传递一组值。我用火鸟3。如果没有预定义值的数量,如何在单个参数中传递多个值?例如,对于good_id的3个值,我得到错误:

字符串"的转换错误;7802840311461";

create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
begin
for select good_id, good from goods where good_id in (:id)
into :good_id, :good
do suspend;
end

procedure Button1Click(Sender: TObject);
var
str : String;  
i  : Integer;      
begin
Query1.Close;
Query1.SQL.Text := 'select * from sp_goods(:id) ';

with DBGridGoods do
begin
if SelectedRows.Count > 0 then
begin
str := '';
With DataSource.DataSet do
for i := 0 to SelectedRows.Count - 1 do
begin
GotoBookmark(SelectedRows.Items[i]) ;
str := str + FieldByName('good_id').asString + ', ';
end;
str := copy( str, 1, length( str ) - 2 );
end;
end;

Query1.Params[0].AsString:=str;
Query1.Open;

结束;

如果我调用IBExpert 中的存储过程

select * from sp_goods('8403') 

它有效,但

select * from sp_goods('8403','7802')

返回错误

过程sp_goods的输入参数不匹配。

如果我使用查询而不是存储过程,也会发生同样的错误。

我尝试使用数组来表示值,但得到了空数据集:

procedure Button1Click(Sender: TObject);
var
a: array of integer;
begin
Query1.Close;
Query1.SQL.Text := 'select * from sp_goods(:id) ';

setlength(a, 2);
a[0]:= 7802;
a[1]:=8403;
Query1.Params[0].Value:= a;   
Query1.Open;
end;     

在Firebird中无法将一组值传递到单个参数中。

在您的示例中,整个存储过程是没有意义的,并且使用联接将所有值一次选择到原始网格中更简单、更快。如果您希望只获取选定项目的商品,并将其放入单独的网格中,最好的方法是在循环中执行查询,而不是收集ID列表。如果您准备一次查询(在循环内部进行prepare((调用是一个常见的错误(,那么它将非常快。

我过去通过两种方式实现了这一点。一种是使用动态查询,除非没有其他选项,否则这不是您想要做的。

另一种方法是使用此过程我正在从我的档案中拖出来,还有其他方法可以更有效地实现这一点。我提供它是为了展示如何做到这一点。

create or alter procedure "Split_Line"
(  IP_NOTE VARCHAR (16000),
IP_SEP CHAR (1))
returns (
"Index" INTEGER,
"Line" VARCHAR (16000))
as
declare variable lLines varchar (16000);
declare variable lMax   integer;
declare variable lPos   integer;
begin
lMax   = 16000;
lLines = ip_Note;
"Index" = 0;
while (lLines is not null)
do begin
"Line" = null;
lPos   = null;
select "Result" from "Pos" (:Ip_Sep, :lLines) into :lPos;
if (lPos is null or lPos = 0)
then begin
/* Last line with no separator */
"Line" = lLines;
lLines = null;
end
else if (lPos = 1 and lLines = Ip_Sep)
then begin
/* Last char is a separator */
"Line" = '';
lLines = null;
end
else begin
/* Normal Case */
//          "Line" = "SubStr" (:lLines, 1, :lPos-1);
//          lLines = "SubStr" (:lLines, :lPos+1, :lMax);
"Line" = substring (:lLines from 1 for :lPos-1);
lLines = substring (:lLines from :lPos+1 for :lMax);
end
"Index" = "Index" + 1;
suspend;
end
end

您可以使用字符串中以逗号分隔的值和分隔符(本例中为逗号(来调用它。它返回一个您使用的表。

使用示例

select * from "Split_Line" ('x,a,cat', ',')

将返回

索引
1x
2a
3cat

另一种方法是使用动态查询

create or alter procedure sp_goods (id varchar(60))
returns (
good varchar(50),
good_id integer)
as
declare lsql varchar (5000);
begin
lsql = 'select good_id, good from goods where good_id in (' || :id || ')';
for execute statement lsql  
into :good_id, :good
do suspend;
end

缺点

  1. 通常,在编译过程时,会在那个时候准备查询。因此,执行速度更快。对于动态查询Dynamic Sql,每次执行过程时都必须准备查询
  2. 通常,编译过程时,引擎会验证表和字段等。在这种情况下,验证发生在执行时。因此,在构造查询时必须非常小心

注意-我没有时间用一个真正的表来测试它,但它可以编译。(现在是凌晨3点,所以我明天可能会查一下(。我通常不会推荐这个,但每样东西都有一席之地。

相关内容

最新更新