2017-01-30 3 views
2

Итак, у меня есть AdoTable, связанный с базой данных (mdb) и DataSource с ее использованием. Этот DataSource используется DBGrid ...Фильтр AdoDB при объединенных столбцах

Я попытался отфильтровать AdoTable на основе пользовательского ввода. Есть 3 важных столбца: имя, фамилия и идентификатор. Я придумал что-то вроде этого, как временное решение:

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; 

Теперь это будет делать exacly, что я хочу, чтобы это сделать, но это вызывает исключение (EOleException: аргументы имеют неправильный тип, находятся вне допустимого диапазона, или находятся в конфликте друг с другом). Это довольно удивляет меня, поскольку я думал, что он должен вести себя как предложение where в команде sql (и он отлично работает как команда).

Я попытался заменить '&' на '+'. Я мог бы разделить текст ввода, но я не хочу этого делать (он будет работать плохо, если у вас будут такие имена, как Робин ван Перси, Ахмад ибн Ханбал и т. Д.)

В качестве альтернативы я мог бы переписать всю программу использовать запросы вместо таблиц, но я действительно не хочу этого делать (это также означало бы, что я получаю новый пользователь recordSet. EVERYTIME изменит 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%' 

Обратите внимание, что может быть «кп Смит» вместо «John Smith», так что он найдет также «Kann Smithers» и т. Д.

+0

Есть некоторые неизвестные части: Какой тип ID? Ваш код предполагает, что это строка, которая звучит неверно, в основном идентификатор - это номер. Вторая: Какая у вас база данных? Когда вы используете, например, SQL Express «%» правильный, когда вы используете Access, вы должны использовать '*' Можете ли вы показать полученную строку фильтра? –

+0

Идентификатор действительно строка. Это может быть что-то вроде «123abc». И я нашел он-лайн, что Access использует «%» («*» не работает, я пытался). Результирующим фильтром будет «фамилия» и «имя», например «% John Smith%» или имя & «» и фамилия, например «% John Smith%» или ID, например «% John Smith%», если мы ищут имя и фамилию или фамилию и имя & quot; & name как '% 0123abcd%' 'или имя & "" и фамилию наподобие' '% 0123abcd%' 'или ID, например'% 0123abcd% '' ', если мы ищут ID –

+0

Пожалуйста, ответьте на свой вопрос – kobik

ответ

1

Код ниже отлично работает с помощью AdoTable, который обращается к employee ta в базе данных Delphi 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; 

Я думаю, что ваша ошибка, вероятно, заключается в использовании указанного синтаксиса для конкретного доступа. Вы получаете доступ к таблице через уровень ADO и что AFAIK ожидает того же синтаксиса, который вы бы использовали, например. для серверного сервера Sql.

Из вашего комментария кажется, что вы хотите прикрыть случай, когда пользователь вводит в ваш 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; 

Update: Если вы хотите, чтобы позволить пользователю ввести что-то вроде

HN Smith

, то вы можете использовать событие 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; 

Преобразование в строчные, очевидно, игнорировать любой капитализации пользователь мог бы использовать.

+0

Да, но это могло бы найти имя или фамилию ... Правильно? Я получил это на работу, но мне нужны оба: D. В любом случае я благодарю вас за ответ, но я думаю, что уже нашел решение ... –

+0

@ RadimNyč: Извините, что вы подразумеваете под «Мне нужны оба»? Если вы хотите, чтобы фильтр обнаружил записи, в которых имя firtname и lastname содержит то, что находится в Edit1.Text, просто измените «или» в «Фильтр» на «и». – MartynA

+0

Нет ... Мне нужен edit1.text, чтобы быть похожим на «Джон Смит» .. это будет искать имя «Джон Смит» и/или фамилия «Джон Смит», и он ничего не найдет ... –

1

Я нашел это: Using LIKE statement for filtering и использовал принятый ответ, и он работает нормально. (Не удалось найти его раньше, как вопрос весьма отличается)

В таблице фильтра:

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; 

Спасибо за ваше время ... Я оставлю это здесь .. Я думаю, что в конце концов кому-то это понадобится

Смежные вопросы