просмотров:107408 | комметариев: 80
Фильтрация данных в Delphi.

Хочу рассказать о нескольких полезных способах фильтрации данных, которые можно применить, чтобы достигнуть эффекта отсеивания данных, по мере ввода искомой строки. На пример в таблице есть столбец "Фамилия", пользователь вводит в поле поиска последовательно буковки и данные фильтруются(отсеиваются) - пользователь ввел первую буковку и выводятся все фамилии, начинающиеся с первой буквы, потом только те которые начинаются с первой и второй и т.д. пока не найдет , что то полезное или вообще ничего не найдет. Т.е. фильтрация происходит не по полному совпадению, а по части введенной пользователем строки. Так же будут приведены способы фильтрации по нескольким полям.

Немного теории.

Основное преимущество фильтров по сравнению с поиском состоит в том, что применять фильтр можно без всяких подготовительных действий над набором данных, так как фильтры не используют индексы. Один минус - фильтрация выполняется медленнее чем поиск основанный на индексах.

Есть два варианта с помощью которых можно задать условие на фильтрацию. Можно использовать их по отдельности или оба сразу.
Первый - строковое значение в свойстве Filter.
Второй - это условие описанное в обработчике события OnFilterRecord.
Начинается фильтрация как только свойство Filtered, установлено в True.

Свойство Filter.

Сначала опишу возможности которые предоставляет свойство Filter, а во второй части главы будет рассказано как можно использовать событие OnFilterRecord. Именно свойство Filter нужно использовать в первую очередь, т.к. это дает значительный выигрыш в производительности при обработке больших по объему наборов данных (по сравнению с событием OnFilterRecord). Особенно это заметно при большом количестве записей в таблице (~свыше 100.000), ну и конечно многое зависит от мощности машины. При малом объеме обрабатываемых данных, разница в скорости не заметна.

Ну что ж приступим. Допустим, есть таблица с полями Фамилия, Имя, Отчество. Нужно фильтровать данные по одному из полей (на выбор), т.е. пользователь должен иметь возможность выбрать по какому из полей фильтровать данные. Для тех кто в танке термины "поле" и "столбец" - обозначают одно и тоже.
Задача стоит такая отсеивать данные по мере ввода искомой строки в Edit.

Кидаем на форму компоненты Combobox и Edit. Combobox будет использоваться для выбора столбца, а в Edit будет вводится искомое слово. Заполняем свойство Items в Combobox именами столбцов. Ставим свойство Style у Combobox равным csDropDownList (чтоб что попало не вводили). Затем в обработчике события Edit1Change пишем следующее:
 

procedure TForm1.Edit1Change(Sender: TObject);
begin
if Length(Edit1.Text) > 0 then
begin
ADOTable1.Filtered:=false;
ADOTable1.Filter:=Combobox1.Text + ' LIKE ' + #39 + Edit1.Text + '%' + #39;
ADOTable1.Filtered:=true;
end
else ADOTable1.Filtered:=false;
end;

Жмем F9 - вуаля. Как видите, все довольно просто. Код простой и понятный. На всякий случай перевожу на русский - если Edit не пустой (при пустом вылетит ошибка), отключаем фильтрацию, формируем строку фильтра, запускаем фильтрацию, если Edit пустой - отключаем фильтрацию.

В самом простом случае, если не нужно давать возможность выбора определенного столбца, а фильтровать по одному конкретному полю(например "ФАМИЛИЯ"), строка фильтра выглядела бы следующим образом:
 

ADOTable1.Filter:='ФАМИЛИЯ LIKE '+ #39 + Edit1.Text + '%' + #39;
 

Строка-условие фильтра означает следующее - выбрать те записи из столбца 'ФАМИЛИЯ', которые начинаются с тех же символов, что и набраны в Edit1.Text.
Особое внимание обратите на пробелы - "потеряете" пробел - не будет работать.

Ключевое слово LIKE позволяет по заданному шаблону сравнивать строки. При этом нужно знать следующее:
символ '_' (подчеркивание) – заменяет любой одиночный символ,
символ '%' (процент) – заменяет любую последовательность из символов.

Знак #39 - означает номер символа ' (одинарная кавычка) в кодовой таблице ASCII. Дело в том, что значение на фильтрацию нужно указывать в одинарных кавычках, а так как одинарные кавычки используются в Delphi для ограничения строк, то чтобы внутри строки поставить одинарную кавычку, её нужно поставить дважды. Конструкция #39 + Edit1.Text + '%' + #39 идентична '''' + Edit1.Text + '%' + ''''. Неправда ли первый вариант как-то попонятней. Можно также использовать спец. функцию QuotedStr, которая возвращает строку окаймленную одинарными кавычками.
В общем следующие три варианта формирования строки абсолютно одинаково работают и какой вариант проще использовать, решайте сами.
 

ADOTable1.Filter:='ФАМИЛИЯ LIKE '+ '''' + Edit1.Text + '%' + '''';
ADOTable1.Filter:='ФАМИЛИЯ LIKE '+ QuotedStr(edit1.Text+ '%');
ADOTable1.Filter:='ФАМИЛИЯ LIKE '+ #39 + Edit1.Text + '%' + #39;

Идем дальше. Если, например, нужно искать любое вхождение искомой строки в записях, а не начиная с первого символа, то строка фильтра выглядела бы следующим образом:
 

ADOTable1.Filter:='ФАМИЛИЯ LIKE ' + #39 + '%' + Edit1.Text + '%' + #39;

Заметили '%' перед Edit1.Text? Переводится так - выбрать те записи из столбца 'ФАМИЛИЯ', в которых есть последовательность символов, которые набраны в Edit1.Text.

Все это прекрасно, но часто нужно фильтровать по нескольким столбцам. Тут применяется немного др. конструкция.
Добавим еще два компонента Edit на форму. Combobox использовать не будем, его можно удалить, т.к. у нас каждое поле (Edit) будет отвечать за ввод информации по определенному столбцу. Еще добавим кнопочку, она будет запускать фильтрацию. Казалось бы следующая конструкция должна корректно работать:
 

procedure TForm1.Button1Click(Sender: TObject);
begin
ADOTable1.Filtered:=false;
ADOTable1.Filter:='ФАМИЛИЯ LIKE '+ #39 + Edit2.Text + '%' + #39 +' AND ' + 'ИМЯ LIKE '+ #39 + Edit3.Text + '%' + #39 + ' AND ' + 'ОТЧЕСТВО LIKE ' + #39 + Edit4.Text + '%' + #39;
ADOTable1.Filtered:=true;
end;

Она и работает, но только в том случае, если данные введены во все три поля. Если одно из полей ввода(Edit) пустое - вылетает ошибка "Аргументы имеют неверный тип".
Впрочем, есть способ с этим бороться. Сначала код:
 

procedure TForm1.Button1Click(Sender: TObject);
var filtr, // формируемая строка фильтра
add: string;
begin
ADOTable1.filtered:=false;
filtr:='';
if length(edit2.text) > 0 then
filtr:= 'ФАМИЛИЯ LIKE '+ #39 + Edit2.Text + '%' + #39;

if length(edit3.text) > 0 then
begin
if length(filtr) > 0 then add:= ' and ' else add:='';
filtr:=filtr + add + 'ИМЯ LIKE '+ #39 + Edit3.Text + '%' + #39;
end;

if length(edit4.text) > 0 then
begin
if length(filtr) > 0 then add:= ' and ' else add:='';
filtr:=filtr + add + 'ОТЧЕСТВО LIKE '+ #39 + Edit4.Text + '%' + #39;
end;

if length(filtr) > 0 then
begin
ADOTable1.Filter:= filtr;
ADOTable1.filtered:=true;
end
else Showmessage('Все поля пусты!');

end;

Смысл такой, нужно провести проверку, пустое поле ввода или нет, а затем уже формировать строку фильтра. Причем начиная со второго поля ввода нужно проверять и строку фильтра. Это нужно для последующего правильного формирования строки.
Например если поле Edit2(Фамилия) пустое, то соответственно и строка фильтра будет пуста(filtr:='') , а, например, поле Edit3(ИМЯ) заполнено, это значит строка фильтра должна иметь вид 'ИМЯ LIKE ' + #39 + Edit3.Text + '%' + #39 ,
а не ' and ' + 'ИМЯ LIKE '+ #39 + Edit3.Text + '%' + #39 , (т.е. без ' and ' вначале).
Следующий фрагмент кода это и выполняет:
 

.....
if length(edit3.text) > 0 then
begin
if length(filtr) > 0 then add:= ' and ' else add:='';
filtr:=filtr + add + 'ИМЯ LIKE '+ #39 + Edit3.Text + '%' + #39;
end;
.....

Опять перевожу - если Edit3 не пустое, то проверяем строку фильтра(filtr) если она не пуста, то прибавляем к сторке фильтра ' and ' + 'ИМЯ LIKE '+ #39 + Edit3.Text + '%' + #39, если пуста, то просто 'ИМЯ LIKE '+ #39 + Edit3.Text + '%' + #39.

Все. В конце присваиваем сформированную строку(filtr) свойству ADOTable1.Filter и запускаем фильтрацию.

.....
if length(filtr) > 0 then
begin
ADOTable1.Filter:= filtr;
ADOTable1.filtered:=true;
end
else Showmessage('Все поля пусты!');
.....

Соответственно, если на этом этапе filtr='', значит ни одно из полей не было заполнено, о чем и выводим соответствующую надпись.

Объяснение немного запутанное, но стоит внимательно посмотреть на код и все станет ясно. Забегая вперед, скажу, что если использовать событие OnFilterRecord, то необходимость в проверке наличия символов в поле ввода отпадает(т.е. его удобней и проще использовать), но при этом падает скорость фильтрации. Впрочем это заметно только при обработке больших по объему наборов данных. Напоследок скажу, кроме операции and можно использовать и другие логические операции or, not, xor, при формирования строки-условия фильтрации по нескольким столбцам, хотя такая необходимость возникает достаточно редко.
Здесь можно скачать рабочий пример фильтрации на основе свойства Filter.
 

Событие OnFilterRecord.

Разберемся с событием OnFilterRecord.
Посмотрим на заголовок процедуры
 

procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean);

DataSet - имя фильтруемого набора данных. Accept имеет тип Boolean, а это значит может принимать два значения true - принять запись, false - отклонить. Кто не дружит с английским перевожу: accept -принимать, брать, соглашаться.
Принцип такой - в обработчике OnFilterRecord последовательно перебираются все записи определенного поля(полей) таблицы данных на предмет соответствия условию фильтрации.
Для наглядности несколько примеров:
Напомню еще раз, что Accept - переменная булевского типа, а это значит можно применять логические операторы(=, <>, <, >, <=, >=, and, or, not) для присвоения ей некоторого значения.
Допустим, в таблице есть поля ГОД и МЕСЯЦ которые имеют целочисленный тип и содержат год и месяц рождения кого либо.
 

TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
Accept:= (DataSet['ГОД'] > 1973);
end;
Где то в программе

Table1.Filtered:=true;

В результате в DBGrid отобразятся записи, у которых значение поля ГОД больше 1973.
Если написать в обработчике такую строку:
 

Accept:= (DataSet['ГОД'] > 1973) and ((DataSet['МЕСЯЦ'] > 5) and (DataSet['МЕСЯЦ'] < 9));

то отобразятся записи тех людей, которые родились после 1973 год летом.
По-моему все понятно - DataSet['ИМЯ_СТОЛБЦА'] "вытягивает" очередное значение записи указанного столбца, а дальше Accept:= некоторое_логическое_условие;
Ради эксперимента поставьте Accept:=true; и выведутся все записи, если Accept:=false; - ни одной.

Если по какой-то причине Вы хотите обратится к DataSet не по имени столбца, а по его номеру, то можно использовать конструкцию DataSet.Fields[НОМЕР_СТОЛБЦА].AsString вместо DataSet['ИМЯ_СТОЛБЦА'].

С теорией покончено, переходим к практике.

Допустим, в таблице есть поле ФАМИЛИЯ (тип строка) и есть поле ввода искомой строки - Edit1.
Нам нужно, чтобы при вводе очередного символа происходила фильтрация (сначала по первому символу, потом по первому и второму и т.д.). Другими словами, нужно определить некоторое условие в OnFilterRecord, а в обработчике события OnEdit1Change запустить фильтрацию - Table1. Filtered:= true;.
Итак начнем ваять OnFilterRecord.
 

procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
var FieldVal:string;
begin
FieldVal := DataSet['ФАМИЛИЯ'];
Accept := copy(FieldVal, 1, length(edit1.text)) = edit1.Text;
end;

FieldVal - значение очередной записи в заданном столбце, в нашем случае в столбце ФАМИЛИЯ.
Дальше так - функция copy копирует часть строки переменной "FieldVal" начиная с первой позиции "1" на длину искомой строки "length(edit1.text)", потом идет сравнение строки полученной с помощью функции copy и строки введенной в edit1.Text. Если строки совпадают, то запись принимается, если нет - не принимается.
Если фильтрация должна происходить без учета регистра букв, то обработчик должен иметь следующий вид:
 

FieldVal := DataSet['ФАМИЛИЯ'];
Accept := copy(AnsiUpperCase(FieldVal), 1, length(edit1.text)) = AnsiUpperCase(edit1.Text);

Осталось только активизировать наш обработчик, как уже говорилось выше в событии OnEdit1Change примерно так:
 

procedure TForm1.Edit1Change(Sender: TObject);
begin
table1.Filtered:=false;
table1.Filtered:=true;
end;

Вот и все. Почти. Есть еще один способ "посимвольной" фильтрации, но он работает немного не так как предыдущий пример. Сначала приведу код:
 

procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
accept:=pos(Edit1.Text, DataSet['ФАМИЛИЯ'])<>0;
end;

Функция Pos осуществляет поиск вхождения подстроки в строку, если подстрока найдена то возвращается позиция вхождения указанной последовательности символов в указанную строку, но это нам не интересно, интересно то, что если в указанной строке нет заданной последовательности символов, то функция возвращает ноль. То есть если в любом месте строки содержащей фамилию (а не только начиная с первой буквы, в этом и отличие) будет найдена искомая комбинация символов, то запись принимается.
Если фильтрация должна происходить без учета регистра букв, то строка должна иметь следующий вид:
 

accept:=pos(AnsiUpperCase(Edit1.Text), AnsiUpperCase(DataSet['ФАМИЛИЯ']))<>0;

Да, еще иногда нужно знать, сколько записей находится в отфильтрованном DataSet, для этого можно использовать свойство RecordCount. Оно возвращает текущее число записей в наборе данных. Например можно применить следующую конструкцию:
 

Label1.Caption := IntToStr(table1.RecordCount);

В данном случае ее можно разместить в обработчике события OnEdit1Change сразу после активизации процедуры фильтрации.
Здесь можно скачать рабочий пример фильтрации на основе события OnFilterRecord.


PS. Каждый из способов имеет свои преимущества и недостатки. Свойство Filter дает ощутимый выигрыш в скорости обработки данных, а событие OnFilterRecord намного "гибче" и удобней в использовании. Применяйте свойство Filter в тех случаях если можно обойтись без использования OnFilterRecord.
Если же Вы применяете оба способа, то стоит помнить, что обработчик события дополняет, а не замещает свойство Filter, т.е если включена фильтрация и св-во фильтр содержит значение фильтра, то обработчик события OnFilterRecord и фильтр(Filter) связаны логическим отношением "AND" (выполняются оба).

Спасибо за внимание. Вопросы, жалобы, предложения оставляйте в гостевой или пишите на gubarevm@mail.ru. Удачи.

Лучшая награда, это положительная рекомендация и ссылка на статью ;)

Автор Губарев Михаил

просмотров:107408 | комметариев: 80
slaff
27 мая 2008, 11:44
Спасибо! Очень нужная вещь!
Кое-что было известно, но теперь такие вещи буду знать наверняка=)
Александр
19 июля 2008, 20:16
Спасибо! Очень помогло :-)
Geralld
16 октября 2008, 18:00
Подскажите, пожалуйста, почему у меня после первой фильтрации выбирается нормально, далее я делаю сброс
Table1.Filtered:=false;
Table1.Filtered:=true;
но следующая фильтрация происходит уже в предыдущей выборке?
Губарев Михаил
18 октября 2008, 20:59
Geralld киньте на маил home7519@yandex.ru, свой проэкт если возможно или код в студию.
Geralld
20 октября 2008, 12:58
К сожалению, знак перехода на новую строку не работает при написании комментариев.
Извиняюсь за неудобочитаемый код.
Губарев Михаил
21 октября 2008, 19:53
Оказалось это проблема в самом компоненте TTable.
Она решается установкой OnFilterRecord := nil; и последующим запуском его.
В ближайшем будущем эта проблема будет освещена в данной статье.
Вам Geralld выслал на мыло проект с нужными исправлениями.
Geralld
22 октября 2008, 17:37
Спасибо автору за отличную и информативную статью - очень помогло и не потребовалось читать хелпы ;-)

ЗЫ: проблему помог решить Михаил путем добавления небольшой процедурки, в которой при новом поиске фильтррекорд нилируется:

procedure TForm1.UpdateFilter(DataSet: TDataSet);
var
FR: TFilterRecordEvent;
begin
with DataSet do
begin
FR := OnFilterRecord;
if Assigned(FR) and Active then
begin
DisableControls;
try
OnFilterRecord := nil;
OnFilterRecord := FR;
finally
EnableControls;
end;
end;
end;
end;
Губарев Михаил
27 октября 2008, 13:15
Трабл с переходом на новую строку при написании коментариев устранен. Поэтому решил пересказать предыдущий пост в более удобочитаемом виде:



Проблемма лечится следующим образом:

1. Пишите следующую процедурку:



procedure TForm1.UpdateFilter(DataSet: TDataSet);

var

FR: TFilterRecordEvent;

begin

with DataSet do

begin

FR := OnFilterRecord;

if Assigned(FR) and Active then

begin

DisableControls;

try

// МАГИЯ ЗДЕСЬ

OnFilterRecord := nil;

OnFilterRecord := FR;

finally

EnableControls;

end;

end;

end;

end;



2.При запуске фильтрации пишем следующее:

.....

Table1.Filtered:=false;

Table1.Filtered:=true;

// вызов процед
уры

UpdateFilter(Table1);

.....
ProStreet
16 Февраля 2009, 14:55
Спасибо за статью! Помогло неимоверно!!!
Frost
29 апреля 2009, 12:48
Автору огромное СПАСИБО!
Smoke8723
08 июня 2009, 02:43
Спасибо за статью! Пол часа гуглил так ничего конкретного не нашел пока не наткнулся на Вашу статью!

Карабаш
06 августа 2009, 00:12
Очень обстоятельная статья и, тем самым, весьма полезная для начинающих (да и не только). Более полного освещения темы что-то не встречал.

Есть предложение слегка продолжить это направления и сделать статью про сортировку. Тоже достаточно актуально для многих. Всегда путаются (или не знают) в чем отличие свойств IndexFieldNames и IndexName. Опять же, про то как сделать сортировку по убыванию значений. И прочие проблемы сортировки.
Лена
10 сентября 2009, 11:30
За статью спасибо! А еще у меня вопрос - нельзя ли как то осуществлять фильтрацию не только по одной подстроке. Если пользователь не знает точного названия, а скажем помнит начало и конец записи.
Губарев Михаил
15 сентября 2009, 21:37
К сожалению фильтрация не имеет той гибкости что и SQL запрос, поэтому можно использовать в строке св-ва FIlter символы подстановки в Like, но работает только символ % (любое кол-во символов (в том числе нулевое)) и то только в начале и в конце строки.

Поэтому вижу один выход, использование SQL запросов с помощью Query. Я уже побывал в Вашей шкуре, когда для осуществления подобной возможности пришлось проект почти с нуля переписывать. Но это стоит того. SQL выполняются быстрее и возможности ограничены полетом фантазии.

Все-таки мой Вам совет - переходите на SQL.

Посмотрите исходники Телефонного справочника на моем сайте, хотя Вам там наверно нелегко будет разобраться. Если, сами на найдете выход из ситуации, то могу сделать учебный проект и выслать вам на мыло.
Новиков Дмитрий
16 ноября 2009, 06:41
Огромное Вам спасибо! Ваша статья очень мне помогла.
Владимир
19 декабря 2009, 20:31
Это всё хорошо конечно, НО как в ADOTable без использования запросов т.е. ADOQuery, сделать поиск числового поля, например номеров телефонов???
Губарев Михаил
20 декабря 2009, 20:34
Проще всего использовать событие onFilterRecord.

В обработчике события пишете примерно следующее:

.........

Accept:= (DataSet['ТЕЛЕФОН'] = 112233);

..........

// где-то в программе запускаете фильтрацию

adoTable1.Filtered:=true;



В статье подобный случай описан.





Владимир (KZ)
04 января 2010, 22:16
Я не "Pro" на в программирование, поэтому может мой вопрос ламерский незнаю...

В общем сабж, есть Form1 на ней лежит DBGrid, DataSource, ADOConnection, ADOTable и 3 Edita.

По первым двум Edita'м происходит фильтрация по частичному совпадению вот так:{ 'Field LIKE '+ #39 + sEdit1.Text + '%' + #39;} все нормально.

А вот в третьем Edit'е должна происходить фильтрация

по числовому полю, т.е. Если я в edit'e напишу 21

то мне нужно что бы в DBGrid'e отображались записи

21

213

2134

2145

Т.е. аналогично первым двум edit'ам.

Знаки = не радуют.

Уже второй день борюсь с этой для кого то ничтожной проблемой, на форумах сплошной СTRL+C CTRL+V.

Люди добрые подскажите кодингом, как можно это организовать.

Извиняюсь что пишу в комментах.

Заранее спасибо.





Владимир (KZ)
04 января 2010, 22:50
УРА!!!!!!

До МЕНЯ ДОПЕРЛО!!!!!!!!!

Губарев Михаил БОЛЬШОЕ ТЕБЕ Человеческое СПАСИБО ЗА ТВОЮ СТАТЬЮ ОСОБЕННО ЗА OnFilterRecord!!!!



КОМУ НАДО ВОТ НАШ КОДИНГ!!!

Итак AdoTable |ONFilterRecord Пишем:



procedure TForm1.ADOTable1FilterRecord(DataSet: TDataSet; var Accept: Boolean);



var FieldVal:string;

begin

FieldVal := DataSet['Tel'];//Tel - имя столбца

Accept := copy(FieldVal, 1, length(sedit3.text)) =sedit3.Text; //вместо sedit3.text пишите свой



В Edite|ONchange пишем:

procedure TForm1.sEdit3Change(Sender: TObject);

Adotable1.Filtered:=false;

Adotable1.Filtered:=true;



И радуемся как Я :))





Санёк
14 марта 2010, 19:11
Если использовать Table вместо ADOTable, то вместо "%" надо ставить "*".

и если нужно искать любое вхождение искомой строки в записях, то это с "*" не работает.
Губарев Михаил
14 марта 2010, 19:51
Санёк, это от не от компонента, а от конкретной СУБД зависит.

Артем
07 января 2011, 17:09
//ADOTable1Fil.Filter



а что у вас означает ADOTable1Fil ? вроде как и компонент, но его нет, в общем не компилится упорно именно из-за этой фиговины, а так спасибо, единственная толковая статья на эту тему, хотя и она из-за этого косяка не помогла(
Губарев Михаил
09 января 2011, 14:33
Досадная опечатка, подправил. Есть же ссылка на рабочий пример фильтрации, скачайте там всего 18кб, посмотрите.
Олег
15 января 2011, 09:47
Помогите пожалуйста. отсеивающий фильтр не работает все сделал как в статье не получилось. База через Аccess.

Когда работаю с базой Paradox все работает исправно.

как это можно сделать в Accesse.
Губарев Михаил
15 января 2011, 21:43
Перешлите проект на маил(в контактах гляньте), сходу причину сказать не могу. Еще можно спросить на http://programmersforum.ru/ там вам наверное быстрее ответят.
Олег
20 января 2011, 12:31
Большое спасибо Михаил!!! Все работает! Очень благодарен Вам за эту статью!
НаЗиРа
13 апреля 2011, 15:31
отличнооооо!!!!
Гена
03 мая 2011, 23:25
Молорик!!!!Очень мне помог!!!Спасиб огромное!!!!)))
morro
11 мая 2011, 14:58
Почитал, попробовал, понравилось, пользуюсь.

Спасибо за прекрасную статью.
Элеонора
21 мая 2011, 15:01
Подскажите как сделать фильтрацию по числовым значениям. Например поле а-числовое. Необходимо найти все данные таблица при a>=Q
Губарев Михаил
24 мая 2011, 00:09
см. комент №18
Элеонора
28 мая 2011, 14:13
Михаил спасибо. Уже разобралась.

Accept:= (DataSet['цена'] > strtoint(a1)) and (DataSet['цена'] < strtoint(a2));
Николай
09 июня 2011, 04:21
при использовании

procedure TForm1.Edit1Change(Sender: TObject);

begin

if Length(Edit1.Text) > 0 then

begin

ADOTable1.Filtered:=false;

ADOTable1.Filter:=Combobox1.Text + ' LIKE ' + #39 + Edit1.Text + '%' + #39;

ADOTable1.Filtered:=true;

end

else ADOTable1.Filtered:=false;

end;



вылетает ошибка:Аргументы имеют неверный тип, выступают за границы диапазона или вступают в конфликт друг с другом
Губарев Михаил
11 июня 2011, 12:58
Николай, LIKE работает только с текстовыми типами полей. У вас кокой тип поля?
Марго
07 июля 2011, 13:35
Работаю в Delphi7 СУБД dBase !Y

Таблица Table1:TTable (без ADO ?);

Фильтрация (RGF) состоит из RadioGroup и Edit

Обращение: Procedure TForme.RGF.Click(Sender:TObgect)

begin

Table1.Filtered:=False;

if RGF.ItemIndex=1 then Table1.Filter:='F='''+EF.Text+''''; и т.д.все поля (10) работают хорошо, но для длинных полей хотелось бы как у Вас, но программа ничего не понимает: ни LIKE,ни #39, ни '%' ни '*'

Можно что нибудь сделать с этими СУБД и Table?

Губарев Михаил
10 июля 2011, 00:56
Пришлите на емаил ваш проект, посмотрю, что можно сделать

home7519(пес)yandex.ru
Марго
12 июля 2011, 14:31
Еще раз.Моя программа маленькая как Ваша, но без АDO , но с базой dBase и с BDE и алиасами.Я прочитала Вашу статью про ВDE , но в ней приложение для баз без BDE не читается Очень хочется чтоб было с АДО и без BDE

Если можно, добавьте в эту Вашу маленькую с ADO и фильтрацией еще базу без BDE на 2-3 поля на 2-3 записи

и больше не буду морочить голову.
Марго
12 июля 2011, 14:42
До этого я писала, что на запрос home7519(nec)yandex.ru

ответила: 404 not found, но письмо не записалось
Губарев Михаил
12 июля 2011, 23:10
Марго, по идее должно работать, уберите ADO везде. Сейчас большая загруженность на работе, просто нет ни на что другое времени, может на выходных, но обещать не буду.

Есть хороший форум программистов, может там есть смысл спросить http://programmersforum.ru/
Маркова Алёна
22 марта 2012, 11:44
СПАСИБО ОГРОМНОЕ за статью!!! Только здесь я нашла, то что искала))))) Но все равно есть вопросы...

Есть Table1, DBGrid1, Edit1

Поиск осуществляется хоть сначала, хоть с середины, без учета регистра НО... ищет только по полю Name1.

Надо следующее: при наборе букв в Эдите он искал и в поле Name1 и в поле Gorod и в других полях

На данный момент код такой...

procedure TForm1.Edit1Change(Sender: TObject);

begin

If length(edit1.text)>0

then

Begin

table1.filtered:=true;

End else table1.filtered:=false;

end;



procedure TForm1.Table1FilterRecord(DataSet: TDataSet;

var Accept: Boolean);

begin

accept:=pos(AnsiUpperCase(Edit1.Text), AnsiUpperCase(DataSet['Name1']))0;

end;
Губарев Михаил
22 марта 2012, 17:27
Маркова Алёна, в статье же описана фильтрация по нескольким полям
Маркова Алёна
22 марта 2012, 22:54
Пробовала добавить такую строчку

accept:=pos(AnsiUpperCase(Edit1.Text), AnsiUpperCase(DataSet['Name1'] and DataSet['Gorod']))0;

Он компилирует :) НО... форма не появляется (((
Маркова Алёна
22 марта 2012, 23:45
Перезапустила Делфи))) Компилировать - компилирует :) Но когда начинаешь пробовать вводить слова для поиска, то ошибка...

Could not convert variant of type (String) into type (Boolean)
Губарев Михаил
23 марта 2012, 05:37
А, ну дак само-сабой! Присмотрелся к вашему коду, куда же вы в AnsiUpperCase пихаете 2 значения с and. Получается вы даете на вход булевое значения, а AnsiUpperCase должно принимать строку.

Нужно, так

accept:=((проверка на pos для первого столбца) or (проверка на pos для второго столбца));
Маркова Алёна
23 марта 2012, 06:32
Михаил, СПАСИБО ОГРОМНОЕ! Работаеееееет!
Маркова Алёна
23 марта 2012, 06:40
Ну вот рано радовалась ((((

Теперь он ищет по городу, а по Name1 не ищет ((((

Код такой...

accept:=(pos(AnsiUpperCase(Edit1.Text), AnsiUpperCase(DataSet['Gorod']))) and (pos(AnsiUpperCase(Edit1.Text), AnsiUpperCase(DataSet['Gorod'])))0;
Маркова Алёна
23 марта 2012, 06:53
Все уже вижу где испавить))))
Маркова Алёна
23 марта 2012, 07:06
Почему то работает через раз. Мне надо следующее...

Я пишу буквы в Эдит, а он ищет совпадения по всем полям
Маркова Алёна
23 марта 2012, 14:28
Михаил, еще раз ОГРОМНОЕ СПАСИБО! Я уже разобралась и теперь работает как надо))))))))

Код такой

accept:=(pos(AnsiUpperCase(Edit1.Text), AnsiUpperCase(DataSet['Name1']))) or (pos(AnsiUpperCase(Edit1.Text), AnsiUpperCase(DataSet['Gorod'])))0;
Дионисий
25 мая 2012, 09:32
Отличная статья очень помогла)))
Игорь Жуковец
14 июня 2012, 18:06
Вот и все. Почти. Есть еще один способ "посимвольной" фильтрации, но он работает немного не так как предыдущий пример. Сначала приведу код:
procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
accept:=pos(Edit1.Text, DataSet['ФАМИЛИЯ'])0);
end;
ошибка в тексте вашем) скобка лишняя
Губарев Михаил
15 июня 2012, 23:46
Спасибо, исправил
Lisavad
04 июля 2013, 07:44
а как можно визвать процедуру OnFilterRecord фильтрации при нажатии на кнопку
Губарев Михаил
05 июля 2013, 14:07
Table1.Filtered:=true; ))))
Светлана
06 июля 2013, 17:34
Спасибо автору за статью!
Алексей
26 августа 2013, 03:48
Здравствуйте.
Интересует как осуществить следующее: имеется поле с 18-ти значным номером, последние 6 цифр - номер изделия. нужно чтобы фильтрация осуществлялась по последним шести цифрам, а первые двенадцать не учитывались при фильтрации.
Губарев Михаил
07 сентября 2013, 14:28
Алексей, думаю так, должно работать в вашем случае:
ADOTable1.Filter:='ВАШЕ_ПОЛЕ LIKE ' + #39 + '%' + Edit1.Text + #39;
Будут найдены записи которые заканчиваются на текст который будет введен в edit1
Таня
16 сентября 2013, 01:51
можно проще пример? Как сделать поиск по Edit. допустим по фамилии. Вводя первую букву "А", нажимая на кнопку поиск, выводились фамилии в таблице, у которых первая буква "А"?
Губарев Михаил
23 сентября 2013, 09:03
procedure TForm1.Button1Click(Sender: TObject);
begin
ADOTable1.Filtered:=false;
ADOTable1.Filter:='ФАМИЛИЯ LIKE '+ #39 + Edit1.Text + '%' + #39;
ADOTable1.Filtered:=true;
end;
Владимир
17 ноября 2013, 18:49
Спасибо!! Действительно стоящая вещь.
Александр
10 декабря 2013, 21:24
Михаил, статья супер!
Подскажи, пожалуйста. При использовании процедуры, расположенной ниже, возникает исключение:"Не удается открыть фильтр". Поле ID_AVTO - числовое. На строковых полях - проблем нет.

procedure TForm1.Edit1Change(Sender: TObject);
begin
if Length(Edit1.Text) > 0 then
begin
DataModule1.ADOTable1.Filtered:=false;
DataModule1.ADOTable1.Filter:='ID_AVTO LIKE ' + #39 + '%' + Edit1.Text + '%' + #39;
DataModule1.ADOTable1.Filtered:=true;
end
else DataModule1.ADOTable1.Filtered:=false;
end;

С уважением, Александр.
Губарев Михаил
21 декабря 2013, 16:15
Александр, LIKE работает только с текстовыми типами полей.
Максим
18 ноября 2014, 19:47
Пробовал делать все выше перечисленые фильтры не полушается. ОШИБКА "аргументы имеют неверный тип выходят за пределы допустимого диапазона" Помогите.
Губарев Михаил
18 ноября 2014, 19:54
Максим, LIKE работает только с текстовыми типами полей. У вас кокой тип поля?
Максим
18 ноября 2014, 20:01
Есть текстовые есть числовые пробовал по разному.Подскажите как навернка посмотреть типы полей?И может ли это быть из-за того что я уже делаю поиск по 1 полю с помощю FilterRecord?
Губарев Михаил
18 ноября 2014, 21:05
Послушайте, скажу честно, я просто не помню. Сейчас уже не занимаюсь прикладным программированием и делфи уже лет пять не открывал. Есть хороший форум программистов http://programmersforum.ru/ можете там зарегаться и спросить.

Извините, что не смог помочь.
Андрей
11 Февраля 2015, 14:41
Фильтр по кириллице работает только так:

procedure Edit_2Exit(Sender: TObject);
begin
ClientDataset.Filtered := false;
ClientDataset.Filtered := true; // //провоцирует срабатывание FilterRecord для ClientDataset
end;


procedure ClientDatasetFilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
Accept := Edit_2.Text = ClientDataset.FieldByName('FIO').AsString;
// здесь можно наворотить кучу Accept-тов по разным полям и Editтам и в конце связать их по and или or
.......
end;

Чем заменить .Locate - так и не нашел. Вместо поиска делаю или такой фильтр или фильтр
по СКуЛ запрросу. SQL не так изячно получается как фильтр и жуть как громоздко, но
говорят быстрее работает.
Губарев Михаил
11 Февраля 2015, 15:02
Хм, почти на 100% уверен, что делал фильтры с данными в кирилице. Может с вашей БД что-то не так?
Андрей
11 Февраля 2015, 15:40
База mdb формат MSAccess2002-2003. И по FilterRecord же работает!)). Похоже с кодировками несвузухи получеются.

Приложение:
Сервер: AdoConnection
ADODatSet (или AdoQuery или AdoTable, но ими не пользуюсь))
DataSetProvider

Клиент:
SocketConnection
ClientDataSet
DataSource
DBGrid или т.п.
-----------

Вот есть такая мысль - вот ADODatSet связан с таблицами через SQL запрос. Так может в SQL как-то писать не просто Поле, а типа AnsiString(Поле). Может есть аналог этой функции в SQL?
Губарев Михаил
11 Февраля 2015, 15:51
>>>Похоже с кодировками несвузухи получеются.
ага, похоже
>>>Может есть аналог этой функции в SQL?
зачем вам это?
Андрей
11 Февраля 2015, 15:55
Чтобы привести текст в одну кодировку с дельфином!
Губарев Михаил
11 Февраля 2015, 16:14
Причем тут тип данных и кодировка?
Андрей
12 Февраля 2015, 09:15
А что тогда причем?
Губарев Михаил
12 Февраля 2015, 09:48
Подозреваю, что дело таки в кодировке данных. Понимаю, что ответ чуть более чем расплывчатый.. Тут спросите http://programmersforum.ru/ возможно помогут
Евгений
08 мая 2015, 13:43
Спасибо за статейку, все подробно расписано, использовал эту информацию как основу для создания фильтрации одной таблицы по полям другой
Айём
22 мая 2015, 08:08
здрасти. у меня проблема в поиск и фильтр не получатся?())))
Губарев Михаил
22 мая 2015, 09:06
И какой ответ вы от меня ждете?
Айём
22 мая 2015, 12:36
что мне делать я заблудился. что мне дальше делать. соединил с база данных что дальше?
Губарев Михаил
22 мая 2015, 13:22
читать мануалы
Евгений
07 декабря 2017, 14:03
Не могу посчитать количество отображаемых записей после фильтрации методом onfilterrecord. Как быть?
просмотров:107408 | комметариев: 80

Оставить комментарий:    

Ваше имя:
 
Текст комментария:
 
+ 1 =