我正在努力使用带有FireDac的in运算符。
我使用的是oracle-database,无法使用简单的查询。
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运算符吗? 如果是这样,它会被替换为什么?
答案 0 :(得分:3)
我刚刚在Embarcadero论坛上发现了this thread用户Serge Girard发布此解决方案:
使用宏而不是以一种不同的方式使用宏
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)';
答案 1 :(得分:2)
如果您询问的是MS Sql Server或具有类似“IN”支持的后端,那么您不能将一系列值指定为查询的IN子句的单个参数。但是,一般(不是特定于FireDAC)的方法,不使用ad-hoc Sql(除非你小心,它具有Sql-Injection的风险)是
使用一系列插入(或.InsertRecords
上的TDataSet
)将“IN”值插入到单列临时表中。这样做的好处是您不受参数化限制在IN列表中特定数量的值。
然后执行“从MyTable中选择*,其中包含SomeColumn(从#MyTempTable中选择ColumnValue)
与仅在ad hoc Sql中指定IN列表值相比,它有点性能,当然,但从下面的示例中可以看出并不多。使用TDFQuery
,创建INList表需要两个步骤,一个用于定义它,另一个用于从中执行Select *。使用TAdoQuery
代替,可以组合这两个步骤。
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查询。
答案 2 :(得分:0)
如果您仍想对列表使用一个参数,则适用于SQL Server:
BCD
KLM
参数的值应该是由您知道不在字段中的字符(例如管道)分隔的任意数量的值:|
如果你通过'M | F',它将带回所有的M和F。
您也可以使用instr函数而不是charindex在Oracle中执行此操作。
我希望这会有所帮助。