ADO数据集多条件组合无法使用Filter最终解决方案

    今天遇到一个问题,查询某部门的数据后,要对这些数据进行多关键字的过滤,当用户在关键字编辑框用空格分开多个关键字,按下回车时就要过滤,将包含所有关键字的记录过滤出来。比如一条记录有20个字段,关键字有3个,当20个字段中的某些字段必须包含这3个关键字才能符合要求,如果只包含1个或2个关键字就要被过滤。

    按照经验我首先想到了ADO的Filter,在关键字编辑框的KeyDown事件里写代码,定义Filter字串,然后Filter,一切都那么熟练,但是问题来了,字串的模型是这样的:(字段1 like '%关键字1%' or 字段2 like '%关键字1%' or 字段3 like '%关键字1%') and
 (字段1 like '%关键字2%' or 字段2 like '%关键字2%' or 字段3 like '%关键字2%') and
 (字段1 like '%关键字3%' or 字段2 like '%关键字3%' or 字段3 like '%关键字3%'),如果这样的模型写成的过滤字串在过滤时一定会出现“参数类型不正确,或不在可以接受的范围之内,或与其他参数冲突。”的错误提示,原因不太清楚,查了网上的资料也没人说的清楚,我的结论是,括号组合不能用and连接,如果括号组合用or 连接是可以的,但又不符合我的业务要求,在做了1天的尝试后,我放弃了,改用OnFilterRecord事件。下面是我的解决方案

一、重点代码

procedure TForm1.ADOQueryListFilterRecord(DataSet: TDataSet; var Accept: Boolean);
var
  i,j,iCount,iTotal:Integer;
  sTmp:string;
  KList:TStrings;
begin
  inherited;
  KList:=TStringList.Create;
  KList.Text:=Trim(RzEdit3.Text); //获取关键字框里的内容
  KList.Text:=StringReplace(KList.Text,' ',#13,[rfReplaceAll]); //空格换成回车,将文字换成列表
  iTotal:=0;
  for i := 0 to KList.Count -1 do
  begin
    if KList[i]<>'' then     //获取有效关键字的总数
      inc(iTotal);
  end;
  if iTotal=0 then    //没有关键字就全部显示
  begin
    Accept:=True;
    Exit;
  end;
  iCount:=0; //匹配计数器清零

  for j := 0 to KList.Count -1 do  //关键字逐一匹配
  begin
    if KList[j]='' then
      Continue;
    for i := 0 to DBGridList.VisibleColumns.Count -1 do   
    //数据集里的字段逐一匹配关键字,我用的是DBGridEh的列,只针对列表里的内容
    begin
      sTmp:=DBGridList.VisibleColumns[i].Field.AsString;  //获取字段内容,全部用字串来匹配
      if Pos(KList[j],sTmp)>0 then     //字串匹配到关键字后,计数器加1
      begin
        Inc(iCount);
        Break;
      end;
    end;

  end;
  Accept:=iCount=iTotal; //是否过滤的判断,这里匹配数要等于关键字的数量才显示,否则过滤掉
end;

说明一下

1、因为是关键字匹配,所以字段的值要转换成字串来比较,包换日期和数字型,如果有Image字段的最好跳过。

2、因为我是用列表显示,是对用户所见的内容进行匹配,所以匹配时用了DBGrid的列数,视情况也可以数据集的全字段匹配比如Query1.Fields之类

3、是否过滤的判断,这里计数器必须与关键字数量相等才显示,也可以转换成匹配度,比如

if iCount*100 / iTotal > 80 then 
  Accept:=true   
else   
  Accept:=false;

二、何时过滤

按照习惯,输入关键字用空格 分开,回车时查找,所以在 关键字编辑框的KeyDown事件里写

procedure TForm1.RzEdit3KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
  i,iTotal:Integer;
  KList:TStrings;
begin
  inherited;

  if Key=VK_RETURN then  //判断是回车才执行
  begin
    KList:=TStringList.Create;
    KList.Text:=Trim(RzEdit3.Text); //获取关键字框里的内容
    KList.Text:=StringReplace(KList.Text,' ',#13,[rfReplaceAll]); //空格换成回车,将文字换成列表
    iTotal:=0;
    for i := 0 to KList.Count -1 do
    begin
      if KList[i]<>'' then     //获取有效关键字的总数,防止用户按了多个空格
        inc(iTotal);
    end;
    if iTotal=0 then    //没有关键字就全部显示
    begin
      Filtered:=False;
      Exit;
    end;
    with ADOQueryList do
    begin
      try
        Filtered:=False;
        Filtered:=True;
      finally
        KList.Clear;
        KList.Free;
      end;

    end;
  end;

end;

说明:

1、2个事件开头部分有些重复,原因是触发过滤的地方可能不止一处,所以有些东西不能省,大家根据需要进行取舍。

2、有些人看到我的代码可能觉得我写的比较啰嗦,其实我觉得宁可多写几行代码也不要出任何漏洞,有时候辛辛苦苦写个软件,就因为有种情况你没想到结果一出现软件就出错了,结果别人就说了一句“什么软件,这也能出错?”,功劳没了,苦劳也没了。写软件难,写没BUG的软件难上加难,完善软件花的时间往往要比写软件多几倍的时间,所以建议大家在写的时候不要急不要浮躁,把所有可能会出现的问题都想一想,在写功能的时候一起补上,看似比别人慢,但最后你的软件是最好的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值