Фильтр AdoDB для объединенных столбцов
Итак, у меня есть AdoTable, подключенный к базе данных (mdb) и DataSource с его помощью. Этот источник данных используется DBGrid...
Я попытался отфильтровать AdoTable на основе ввода пользователя. Есть 3 важных столбца: имя, фамилия и ID. Я придумал что-то вроде этого как временное решение:
AdoTable.filter:='surname like ' +
QuotedStr('%'+edit1.text+'%')+' or name like ' +
QuotedStr('%'+edit1.text+'%')+' or ID like ' +
QuotedStr('%'+edit1.text+'%');
AdoTable.filtered:=true;
Он работает, но он не делает точно то, что я хотел бы, чтобы он делал... (при поиске имени И конечно же имени он ничего не найдет, так как выглядит только в одном столбце). Итак, позже я изменил свой код в это:
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: Аргументы имеют неправильный тип, находятся вне допустимого диапазона или конфликтуют друг с другом). Это довольно удивляет меня, так как я думал, что он должен вести себя как пункт where в команде sql (и он отлично работает как команда).
Я попытался заменить '&' на '+'. Я мог бы разделить вводимый текст, но я не хочу этого делать (это будет плохо работать, если у вас будут имена, такие как Робин ван Перси, Ахмад ибн Ханбал и т. Д.)
В качестве альтернативы я мог бы переписать всю программу, чтобы использовать запросы вместо таблиц, но я на самом деле не хочу этого делать (это также означало бы, что я получу новый recordSet КАЖДЫЙ пользователь изменил бы 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", поэтому он также найдет "Kan Smithers" и т. Д.
2 ответа
Приведенный ниже код отлично работает с AdoTable, который обращается к employee
стол в Дельфи dbdemos.mdb
база данных. Мой 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, который вы упомянули Вы получаете доступ к таблице через уровень ADO, и этот AFAIK ожидает того же синтаксиса, который вы использовали бы, например, для серверной части Sql Server.
Из вашего комментария кажется, что вы хотите охватить случай, когда пользователь вводит в ваш Edit1.Text фрагмент имени, за которым следует пробел, за которым следует фрагмент или фамилия. Следующее сделает это:
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, очевидно, должно игнорировать любую заглавную букву, которую мог использовать пользователь.
Я нашел это: с помощью оператора LIKE для фильтрации и использовал принятый ответ, и он работает просто отлично. (Не могу найти его раньше, так как вопрос совсем другой)
На табличный фильтр:
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;
Спасибо за ваше время... Я оставлю это здесь.. Я думаю, в конце концов, кому-то это может понадобиться