SQL 使用 "in" 子句准备参数 FireDac

SQL Prepared Parameter FireDac using "in"-clause

我在 FireDac 中使用 in 运算符时遇到困难。

我正在使用 oracle 数据库,无法进行简单的查询。

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

FDQuery1.ParamByName('Genders').AsString:= 'M';

它使用一个参数,但这显然不是 in 运算符的目的。

但是多个值不起作用:

FDQuery1.ParamByName('Genders').AsString:= 'M, F';
FDQuery1.ParamByName('Genders').AsString := '''M'', ''W''';

难道是不支持in运算符? 如果是这样,它会被什么取代?

如果您询问的是 MS Sql 服务器或对 "IN" 具有类似支持的后端,那么您不能将一系列值指定为 IN 的单个参数查询的子句。但是,不使用临时 Sql(除非您小心,否则会带来 Sql-注入的风险)的一般(非 FireDAC 特定)方法是

  • 使用一系列插入(或 TDataSet 上的 .InsertRecords)将 "IN" 值插入到单列临时 table.这样做的好处是您不会被参数化限制为 IN 列表中特定数量的值。

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

当然,与仅在 ad hoc Sql 中指定 IN 列表值相比,它的性能有所提高,但从下面的示例中可以看出并不多。使用 TDFQuerys,INList table 的创建需要两个步骤,一个是定义它,另一个是从它做一个 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;

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

我刚刚在用户 Serge Girard 发布此解决方案的 Embarcadero 论坛上找到 this thread

改用宏,也许方式略有不同

SELECT * FROM `table` !mysel
and
Query.macrobyname('mysel').asraw:='WHERE Field in (1,2,3)';

SELECT * FROM table WHERE !mysel

no selection Query.MacroByName('mysel').asRaw:'1=1';
a selection Query.MacroByName('mysel').asRaw:'Field in (1,2,3)';

如果您仍想对列表使用一个参数,这适用于 SQL 服务器:

SELECT * FROM Customers WHERE charindex(Gender, :Genders) > 0

参数的值应该是任意数量的值,由您知道字段中不存在的字符(例如竖线)分隔:|

如果您通过 'M|F' 它将带回所有 M 和 F。

您也可以在 Oracle 中使用 instr 函数而不是 charindex 来执行此操作。

希望对您有所帮助。