我在delphi项目中使用Zeos和mysql。 我想做的是使用文本框过滤数据集。
要做到这一点,我在文本框'OnChange'事件中使用以下查询:
ZGrips.Active := false;
ZGrips.SQL.Clear;
ZGrips.SQL.Add('SELECT Part_Name, Description, OrderGerman, OrderEnglish FROM Part');
ZGrips.SQL.Add('WHERE Part_Name LIKE ' + '"%' + trim(txt_search.Text) + '%"');
ZGrips.Active := true;
运行并在文本框中输入第一个字符后,我在DBGrid中得到空数据集, 所以DBGrid什么也没有显示,那么如果我输入第二个字符,我会在DBGrid中得到一些结果。甚至更奇怪的行为:如果我在我的SQL查询中使用AS Clause,如:
Part_Name AS blablabla,
Description AS blablabla,
OrderGerman AS OG,
OrderEnglish AS OE
在这种情况下,DBGrid只显示2列:Part_Name和Description,我不明白它为什么忽略第3和第4列。
感谢您提前提供任何帮助。
答案 0 :(得分:2)
始终使用参数
首先,您需要使用参数,否则当用户在搜索框中输入错误的字符时,您的查询将会中断或更糟
见:How does the SQL injection from the "Bobby Tables" XKCD comic work?
参数还使您查询更快,因为数据库引擎只需要解码一次查询
如果更改参数,引擎将知道查询本身未更改,并且不会对其进行重新解码。
请勿使用clear
和add
只需一次性提供SQL作为文本,它就会更快
这是特别的。如果在循环中,在循环外部您将不会注意到差异。
您的代码应该是这样的:
procedure TForm1.SetupSearch; //run this only once.
var
SQL: string;
begin
ZGrips.Active:= false;
SQL:= 'SELECT Part_Name, Description, OrderGerman, OrderEnglish FROM Part' +
'WHERE Part_Name LIKE :searchtext'); //note no % here.
ZGrips.SQL.Text:= SQL; //don't use clear and don't use SQL.Add.
end;
//See: http://docwiki.embarcadero.com/Libraries/XE2/en/Vcl.StdCtrls.TEdit.OnChange
procedure TForm1.Edit1Change(Sender: TObject);
begin
if Edit1.Modified then begin
Timer1.Active:= true;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Active:= false;
if Edit1.Text <> ZGrips.Params[0].AsString then begin
ZGrips.Params[0].AsString:= Edit1.Text + '%'
ZGrips.Active:= true;
end;
end;
使用计时器
根据@ MartinA的建议,使用计时器并且只是经常启动查询
您获得的奇怪行为可能是因为您在旧查询有时间完成之前停止并重新激活新查询。
Params[index: integer]
属性比ParamsByName属性快一点
虽然这在循环之外并不重要。
允许数据库使用索引!
仅使用尾随通配符%
比使用前导通配符更快,因为数据库只能使用索引,因为有一个尾随通配符。
如果要使用前导通配符,请考虑以相反的顺序存储数据并使用尾随通配符。
全文索引要好于
当然,如果同时使用前导和后续外卡,则必须使用全文索引
在MySQL中,您使用MATCH AGAINST
语法,而不是使用{{1}}语法
见:Differences between INDEX, PRIMARY, UNIQUE, FULLTEXT in MySQL?
并且:Which SQL query is better, MATCH AGAINST or LIKE?
最新版本的MySQL支持InnoDB中的全文索引 记得永远不要使用MyISAM,它不可靠。