Delphi新手求助:如何从.ini文件执行动态SQL查询?
Delphi动态执行INI文件中带IN条件的查询
需求说明
作为Delphi编程新手,需实现以下功能:
- 从DBGrid中选择若干文件名,确认后点击按钮执行查询
- 查询语句存储在.ini文件中,需根据每次选择的不同文件名动态生成正确的IN子句
现有文件与代码
Queries.ini内容
[Query] QSELECTEDFN=SELECT * FROM TEST_01 WHERE FILE_NAME IN (:FILE_NAME);
当前Delphi代码
ini := TIniFile.Create('C:\file dir\Queries.ini'); try qSlctdByFN := ini.ReadString('QUERY', 'QSELECTEDFN', ''); ADOQuery1.SQL.Clear; ADOQuery1.SQL.Text := qSlctdByFN; ADOQuery1.Parameters.ParamByName('FILE_NAME').Value := slselectedFN.CommaText; ADOQuery1.Active := true; finally ini.Free; end;
期望执行结果
- 选择1.txt、2.txt时,执行SQL:
SELECT * FROM TEST_01 WHERE FILE_NAME IN ('1.txt','2.txt');
- 仅选择3.txt时,执行SQL:
SELECT * FROM TEST_01 WHERE FILE_NAME IN ('3.txt');
问题分析
当前代码的核心问题是:将slselectedFN.CommaText直接赋值给单个参数,会让数据库把'1.txt,2.txt'当成单个文件名去匹配,而非两个独立的文件名,无法得到预期结果。
解决方案
方案一:参数化动态生成占位符(推荐,安全无注入风险)
这种方式通过动态生成对应数量的参数占位符,再逐个赋值,完全符合参数化查询的规范,避免SQL注入问题。
步骤1:修改INI文件的SQL模板
将原语句改为带占位标记的模板,方便后续替换:
[Query] QSELECTEDFN=SELECT * FROM TEST_01 WHERE FILE_NAME IN ({PARAMS});
步骤2:修改Delphi代码
var ini: TIniFile; baseSQL: string; i: Integer; paramPlaceholders: string; begin ini := TIniFile.Create('C:\file dir\Queries.ini'); try baseSQL := ini.ReadString('QUERY', 'QSELECTEDFN', ''); paramPlaceholders := ''; // 根据选中文件数量生成参数占位符(如:FN1, :FN2) for i := 0 to slselectedFN.Count - 1 do begin if i > 0 then paramPlaceholders := paramPlaceholders + ', '; paramPlaceholders := paramPlaceholders + Format(':FN%d', [i+1]); end; // 替换模板中的占位标记 baseSQL := StringReplace(baseSQL, '{PARAMS}', paramPlaceholders, [rfReplaceAll]); ADOQuery1.SQL.Clear; ADOQuery1.SQL.Text := baseSQL; // 为每个参数赋值 for i := 0 to slselectedFN.Count - 1 do begin ADOQuery1.Parameters.ParamByName(Format('FN%d', [i+1])).Value := slselectedFN[i]; end; ADOQuery1.Active := True; finally ini.Free; end; end;
方案二:拼接带引号的文件名(不推荐,存在SQL注入风险)
如果是内部可控系统,且文件名不会包含特殊字符,可使用这种方式,但需注意转义单引号:
步骤1:修改INI文件的SQL模板
[Query] QSELECTEDFN=SELECT * FROM TEST_01 WHERE FILE_NAME IN (%s);
步骤2:修改Delphi代码
var ini: TIniFile; sqlTemplate: string; fileNamesStr: string; i: Integer; begin ini := TIniFile.Create('C:\file dir\Queries.ini'); try sqlTemplate := ini.ReadString('QUERY', 'QSELECTEDFN', ''); fileNamesStr := ''; // 拼接带单引号的文件名,转义内部的单引号 for i := 0 to slselectedFN.Count - 1 do begin if i > 0 then fileNamesStr := fileNamesStr + ', '; fileNamesStr := fileNamesStr + '''' + StringReplace(slselectedFN[i], '''', '''''', [rfReplaceAll]) + ''''; end; ADOQuery1.SQL.Clear; ADOQuery1.SQL.Text := Format(sqlTemplate, [fileNamesStr]); ADOQuery1.Active := True; finally ini.Free; end; end;
总结
优先使用方案一,参数化查询不仅能正确匹配多个文件名,还能杜绝SQL注入风险,是数据库操作的标准安全做法。
内容的提问来源于stack exchange,提问作者Hoon Heo
相关产品推荐
相关产品推荐

