合并列上的 AdoDB 过滤器

AdoDB filter on merged columns

所以我有一个 AdoTable 连接到数据库 (mdb) 和使用它的 DataSource。此数据源由 DBGrid 使用...

我尝试根据用户输入过滤 AdoTable。有 3 个重要的列:name、surname 和 ID。我想出了这样的临时解决方案:

AdoTable.filter:='surname like ' +
      QuotedStr('%'+edit1.text+'%')+' or name like ' +
      QuotedStr('%'+edit1.text+'%')+' or ID like ' +
      QuotedStr('%'+edit1.text+'%');
AdoTable.filtered:=true;

它确实有效,但它并没有完全按照我想要的方式执行...(在搜索 name 和 surename 时,它​​不会找到任何内容,因为它只在一列中查找)。 所以后来我把我的代码修改成这样:

AdoTable.filter:='surname & " " & name like ' +
      QuotedStr('%'+edit1.text+'%')+' or name & " " & surname like ' +
      QuotedStr('%'+edit1.text+'%')+' or ID like ' +
      QuotedStr('%'+edit1.text+'%');
AdoTable.filtered:=true;

现在这将完全按照我的要求执行,但会引发异常(EOleException:参数类型错误、超出可接受范围或相互冲突)。 这让我很吃惊,因为我认为它应该像 sql 命令中的 where 子句一样运行(并且它作为命令完美运行)。

我尝试用“+”替换“&”。 我可以拆分输入文本,但我不想那样做(如果你有 Robin van Persie、Ahmad ibn Hanbal 等名字,效果会很差。)

或者,我可以重写整个程序以使用查询而不是表,但我真的不想这样做(这也意味着我将获得新的记录集,每次用户将更改 edit1.text 而不是只是过滤)。

有什么想法吗?

编辑: 所以有效的命令看起来像这样

select * from person where surname & " " & name like '%John Smith%' or name & " " & surname like '%John Smith%' or ID like '%John Smith%'

过滤器看起来像这样(它会触发异常)

surname & " " & name like '%John Smith%' or name & " " & surname like '%John Smith%' or ID like '%John Smith%'

请注意,可能有 'hn Smith' 而不是 'John Smith',因此它也会找到 'Kahn Smithers' 等

下面的代码适用于 AdoTable,它访问 Delphi dbdemos.mdb 数据库中的 employee table。我的 AdoConnection 正在使用 Microsoft Jet 4.0 OLE DB 驱动程序。

procedure TForm1.Button1Click(Sender: TObject);
var
  FilterExpr : String;
begin
  AdoTable1.Filtered := not AdoTable1.Filtered;
  if AdoTable1.Filtered then begin
    FilterExpr := 'FirstName like ' + QuotedStr('%' + Edit1.Text + '%') + ' or LastName like ' + QuotedStr('%' + Edit1.Text + '%');
    AdoTable1.Filter := FilterExpr;
  end;
end;

我认为您的错误可能是使用了您提到的 Access-specific 语法。您正在通过 ADO 层访问 table ,并且 AFAIK 期望使用与您使用的语法相同的语法,例如对于 Sql 服务器 back-end.

从您的评论来看,您似乎想要涵盖用户在您的 Edit1.Text 中键入名字片段后跟 space 片段或片段的情况姓。以下将执行此操作:

procedure TForm1.Button1Click(Sender: TObject);
var
  FilterExpr : String;
  P : Integer;
  S1,
  S2 : String;
begin
  AdoTable1.Filtered := not AdoTable1.Filtered;
  if AdoTable1.Filtered then begin
    P := Pos(' ', Trim(Edit1.Text));
    if P > 0 then begin
      S1 := Copy(Trim(Edit1.Text), 1, P - 1);
      S2 := Copy(Trim(Edit1.Text), P + 1, MaxInt);
      FilterExpr := '(FirstName like ' + QuotedStr('%' + S1 + '%') + ')';
      FilterExpr := FilterExpr + ' or (LastName like ' + QuotedStr('%' + S2 + '%') + ')';
    end
    else
      FilterExpr := 'FirstName like ' + QuotedStr('%' + Edit1.Text + '%') + ' or LastName like ' + QuotedStr('%' + Edit1.Text + '%');
    AdoTable1.Filter := FilterExpr;
  end;
end;

更新:如果你想让用户输入类似

的内容

恩史密斯

那么您可以使用这样的 FilterRecord 事件来代替上面的代码。

procedure TForm1.ADOTable1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
var
  S : String;
begin
  S := LowerCase(DataSet.FieldByName('FirstName').AsString + ' ' + DataSet.FieldByName('LastName').AsString);
  Accept := Pos(LowerCase(Edit1.Text), S) > 0; 
end;

显然,转换为 LowerCase 是为了忽略用户可能使用的任何大写。

我发现了这个:Using LIKE statement for filtering 并使用了公认的答案,它工作得很好。 (无法尽快找到它,因为问题完全不同)

在 table 过滤器上:

procedure TDataModule1.ADOTableFilterRecord(DataSet: TDataSet;
  var Accept: Boolean);
var
  nameSurname :string;
  surnameName :string;
begin
  nameSurname:= DataSet.FieldByName('name').AsString+' '+DataSet.FieldByName('surname').AsString;
  surnameName:= DataSet.FieldByName('surname').AsString+' '+DataSet.FieldByName('name').AsString;

  if assigned(MainForm) then
    Accept := (Pos(MainForm.edit1.Text, nameSurname) > 0)
  or (Pos(MainForm.edit1.Text, surnameName) > 0)
  or (Pos(MainForm.edit1.Text, DataSet.FieldByName('ID').AsString) > 0);
end;

编辑更改:

procedure TMainForm.edit1Change(Sender: TObject);
begin
    DataModule1.AdoTable.Filtered:=false;
    if edit1.Text<>'' then
      DataModule1.AdoTable.Filtered:=True;
end;

谢谢你的时间...我会把它留在这里..我想最终有人会需要它