SQL准备参数FireDac使用"in"-clause

Tom*_*mmy 8 delphi firedac

我正在努力使用带有FireDac的in运算符.

我使用的是oracle-database,无法进行简单的查询.

FDQuery1.SQL.Text := 'SELECT * FROM Customers WHERE Gender in (:Genders)';

FDQuery1.ParamByName('Genders').AsString:= 'M';
Run Code Online (Sandbox Code Playgroud)

它适用于一个参数,但这显然不是in运算符的目的.

但是,多个值不起作用:

FDQuery1.ParamByName('Genders').AsString:= 'M, F';
FDQuery1.ParamByName('Genders').AsString := '''M'', ''W''';
Run Code Online (Sandbox Code Playgroud)

可能是不支持in运算符?如果是这样的话会被替换掉什么?

Mar*_*ynA 2

如果您询问 MS Sql Server 或对“IN”具有类似支持的后端,则无法将一系列值指定为查询的 IN 子句的单个参数。然而,在不使用 ad-hoc Sql 的情况下执行此操作的通用(不是特定于 FireDAC 的)方法(除非您小心,否则会带来 Sql 注入的风险):

  • 使用一系列插入(或.InsertRecords在 上TDataSet)将“IN”值插入到单列临时表中。这样做的优点是您的参数化不受 IN 列表中特定数量的值的限制。

  • 然后执行“Select * from MyTable where SomeColumn in (Select ColumnValue from #MyTempTable)

当然,与仅在 ad hoc Sql 中指定 IN 列表值相比,这会带来一些性能提升,但从下面的示例中可以看出,性能并不高。使用TDFQuerys,创建 INList 表需要两个步骤,一是定义它,二是从中执行 Select *。使用TAdoQuerys 代替,可以将这两个步骤结合起来。

TForm1 = class(TForm)
  FDQuery1: TFDQuery;
  qInlist: TFDQuery;
  [etc]

 const
  scCreateINListTable =
  'if object_id(''tempdb.dbo.#countrycodes'', ''U'') is not null drop table #countrycodes'#13#10
   + 'create table #countrycodes (ACode char(2))';

   scOpenINList = 'select * from #countrycodes';

   scGetClients = 'select * from client where country in (select ACode from #countrycodes)';

procedure TForm1.GetClients;
begin
  qINList.SQL.Text := scCreateINListTable;
  qINList.ExecSQL;

  qINList.SQL.Text := scOpenINList;
  qINList.Open;

  qINList.InsertRecord(['US']);
  qINList.InsertRecord(['GB']);
  qINList.InsertRecord(['IT']);

  FDQuery1.SQL.Text := scGetClients;
  FDQuery1.Open;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  GetClients;
end;
Run Code Online (Sandbox Code Playgroud)

请注意,此实现根本不需要任何参数化或即席 Sql 查询。