Выглядеть он будет у нас вот так…
Можно добавлять бесконечное число параметров для фильтрования. Это начальная версия, я расскажу идею, там ещё много всего надо доработать, но как идея вполне рабочая.
Смысл такой – нам нужно составить запрос к базе визуально, и в секцию where SQL запроса добавить конструкцию вида
1 |
(iOrderID = 10150) or (iOrderID = 10151) or (iOrderID = 10152); |
Но сначала сделаем подготовку. Создадим форму, со скролбоксом, на который будем добавлять фрэймы в TObjectList и далее работать с ним. Как мы будем это делать?
Вот наш TObjectList как поле класса
1 2 3 |
uses System.Contnrs; ... FParamsOL:TObjectList; |
Добавим в конструктор и деструктор соответствующие записи
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
constructor TUsersFilterForm.Create(AOwner: TComponent); begin inherited; FParamsOL:=TObjectList.Create; FParamsOL.OwnsObjects:=true; ilNormal16.GetBitmap(0,bAddParam.Glyph); end; destructor TUsersFilterForm.Destroy; begin FParamsOL.Free; inherited; end; |
По нажатию на добавить параметр будет происходить что-то вроде…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
procedure TUsersFilterForm.bAddParamClick(Sender: TObject); var i:integer; begin i:=FParamsOL.Add(TUsersFilterElementFrame.Create(Self)); with TUsersFilterElementFrame(FParamsOL[i]) do begin TUsersFilterElementFrame(FParamsOL[i]).Name:=TUsersFilterElementFrame(FParamsOL[i]).Name+FCount.ToString; Inc(FCount); top:=TUsersFilterElementFrame(FParamsOL[FParamsOL.Count-1]).Top+TUsersFilterElementFrame(FParamsOL[FParamsOL.Count-1]).Height; parent:=ScrollBox; Align:=alTop; if top=0 then cbConditions.Visible:=false; end; end; |
Модуль элемента фильтра (фрэйм)
Пара комбобоксов и tedit для получения значения.
Нам также понадобится процедура для перестраивания элементов после удаления одного из них
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
procedure TUsersFilterForm.reorderFilterElements; var i,h: Integer; begin h:=0; for i := 0 to FParamsOL.Count-1 do begin if TUsersFilterElementFrame(FParamsOL[i]).Visible then begin TUsersFilterElementFrame(FParamsOL[i]).Top:=h; if h=0 then TUsersFilterElementFrame(FParamsOL[i]).cbConditions.Visible:=false; h:=TUsersFilterElementFrame(FParamsOL[i]).Top+TUsersFilterElementFrame(FParamsOL[i]).Height; end; end; end; |
Нам также понадобится некоторый стартовый запрос, к которому мы будем добавлять ту часть, которая отвечает за фильтрацию, у меня он выглядит так
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
SELECT u.creationDateTime as usersCreationDateTime, u.id as usersID, u.name as usersName, u.family as usersFamily, u.patronymic as usersPatronymic, u.birthday as usersBirthday, u.phone as usersPhone, u.email as usersEmail, r.name as roleName FROM coffeetest_db.users u, roles r where u.roles_id=r.id and u.isFolder=0 |
Ок, к этому запросу нам нужно добавить часть, которая будет отвечать за фильтрацию. Теперь собственно конструирования строки
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
function TUsersFilterForm.BuildSQLRequest: string; function currentConditionToEng(filterFrame:TUsersFilterElementFrame):string; begin if filterFrame.cbConditions.ItemIndex=0 then result:='AND'; if filterFrame.cbConditions.ItemIndex=1 then result:='OR'; end; function currentParamToEng(filterFrame:TUsersFilterElementFrame):string; begin if filterFrame.cbParams.ItemIndex=0 then result:='u.name'; if filterFrame.cbParams.ItemIndex=1 then result:='u.family'; if filterFrame.cbParams.ItemIndex=2 then result:='patronymic'; if filterFrame.cbParams.ItemIndex=3 then result:='birthday'; if filterFrame.cbParams.ItemIndex=4 then result:='phone'; if filterFrame.cbParams.ItemIndex=5 then result:='email'; if filterFrame.cbParams.ItemIndex=6 then result:='CreationDateTime'; end; var i:integer; s:string; filterFrame:TUsersFilterElementFrame; begin // example (iOrderID = 10150) or (iOrderID = 10151) or (iOrderID = 10152); if FParamsOL.Count>0 then begin // getting 1-st value // zero element with TUsersFilterElementFrame(FParamsOL[0]) do begin filterFrame:=TUsersFilterElementFrame(FParamsOL[0]); if TUsersFilterElementFrame(FParamsOL[0]).visible then s:=s+' ('+currentParamToEng(filterFrame)+'='+''''+eValue.Text+''''+') '; end; end; if FParamsOL.Count>1 then begin // getting 2-sd and other values // other elements for i := 1 to FParamsOL.Count-1 do begin with TUsersFilterElementFrame(FParamsOL[i]) do begin if TUsersFilterElementFrame(FParamsOL[i]).visible then begin filterFrame:=TUsersFilterElementFrame(FParamsOL[i]); s:=s+' '+currentConditionToEng(filterFrame)+' ('+currentParamToEng(filterFrame)+'='+''''+eValue.Text+''''+') '; end; end; end; end; |
Ну и финальный аккорд, вызов в том месте, где нам это нужно, будет выглядеть примерно так…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
procedure TUsersAll.Filter(); var filterForm:TUsersFilterForm; begin filterForm:=TUsersFilterForm.Create(Self); try if filterForm.ShowModal=mrOk then begin qSelectUsers.Close; qSelectUsers.SQL.Text:=filterForm.BuildSQLRequest; qSelectUsers.Open(); end; finally filterForm.Free; end; end; |
Не претендую на гениальность. Возможно есть более простые “библиотечные” решения, но я пошел своим путем.
Можно ещё добавить условие Like, дополнительно к “равно”.
С уважением, Пантелеев Станислав (elGringo).