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 列表值相比,它的性能有所提高,但从下面的示例中可以看出并不多。使用 TDFQuery
s,INList table 的创建需要两个步骤,一个是定义它,另一个是从它做一个 Select *。改为使用 TAdoQuery
s,这两个步骤可以合并。
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 来执行此操作。
希望对您有所帮助。
我在 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 列表值相比,它的性能有所提高,但从下面的示例中可以看出并不多。使用 TDFQuery
s,INList table 的创建需要两个步骤,一个是定义它,另一个是从它做一个 Select *。改为使用 TAdoQuery
s,这两个步骤可以合并。
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 来执行此操作。
希望对您有所帮助。