Форум » Clipper » Помогите с реализацией задумки » Ответить

Помогите с реализацией задумки

Softlog86: Привет всем ! Есть задача . Имеется DBF-ка : A ,B ,C, D, - числовые поля (геометрические размеры) CODE - код товара Необходимо сделать фильтрацию по введенным полям да ещё и "приправить " дополнительными формами ввода (от /до) ------------------------------------------------------------------------------------------- | Размер А от [ ] до [ ] | Размер B от [ ] до [ ] | Размер C от [ ] до [ ] | Размер D от [ ] до [ ] | | [Искать] [Выход] | -------------------------------------------------------------------------------------------- Вводим числовые параметры ... По кнопке [Искать] - должно быть отфильтровано по введённым полям Пока продумываю как это лучше реализовать : Форма ввода и алгоритм фильтрации .... Поиск может быть при разном количестве заполненных полей . Разумеется - если поле не заполнено - то оно и не участвует в поиске .... Буду признателен за какие-то примерчики вашей реализации подобного задания ...

Ответов - 26, стр: 1 2 All

PSP: Могу предложить так: [pre2]#define NTRIM( x ) ( AllTrim( Str( x ) ) ) LOCAL cFilter := "" LOCAL nAMin, nAMax LOCAL nBMin, nBMax LOCAL nCMin, nCMax LOCAL nDMin, nDMax ... тут get-ы ... cFilter := IF( ! Empty( nAMin ), "BASE->AMin >=" + NTRIM( nAMin ), "" ) cFilter += IF( ! Empty( nAMax ), IF( ! Empty( cFilter ), ".and.", "" ) + "BASE->AMax <=" + NTRIM( nAMax ), "" ) cFilter += IF( ! Empty( nBMin ), IF( ! Empty( cFilter ), ".and.", "" ) + "BASE->BMin >=" + NTRIM( nBMin ), "" ) cFilter += IF( ! Empty( nBMax ), IF( ! Empty( cFilter ), ".and.", "" ) + "BASE->BMax <=" + NTRIM( nBMax ), "" ) cFilter += IF( ! Empty( nCMin ), IF( ! Empty( cFilter ), ".and.", "" ) + "BASE->CMin >=" + NTRIM( nCMin ), "" ) cFilter += IF( ! Empty( nCMax ), IF( ! Empty( cFilter ), ".and.", "" ) + "BASE->CMax <=" + NTRIM( nCMax ), "" ) cFilter += IF( ! Empty( nDMin ), IF( ! Empty( cFilter ), ".and.", "" ) + "BASE->DMin >=" + NTRIM( nDMin ), "" ) cFilter += IF( ! Empty( nDMax ), IF( ! Empty( cFilter ), ".and.", "" ) + "BASE->DMax <=" + NTRIM( nDMax ), "" ) IF ! Empty( cFilter ) BASE->( DBSetFilter( &( "{ || " + cFilter + "}" ), cFilter ) ) END // IF[/pre2]

PSP: P.S. с добавлением ".and." надо доработать, могут быть ошибки, когда, например, введена только nAMin Upd: Пример изменил. Должно работать. :)

gustow: Не по реализации - чуть в оффтоп... Softlog86 пишет: A ,B ,C, D, - числовые поля (геометрические размеры) Ну, к примеру, A/B/C я понимаю - длина/ширина/высота... а D тогда какой "геометрический размер"? (просто интересно) А по теме - я бы тоже как-то подобно выше написанному стал бы решать.


AndreyZh: Если интересно, то мой "колхозный" подход: в примере поиск, но ... нашел и фильтрацию... крайне медленная операция по сети [pre] * --------------------------------------------------------------------------- * Установка или снятие фильтра на список товаров (снять - пустые значения) STAT PROC pFilterWar() LOCA cOldCol:=SetColor(), GetList:={} cCodGroup := Left(cCodGroup+Spac(2),2) cfName := Left(cfName+Spac(10),10) // Определяю условие фильтрации fSwopen(16,15,4,63,cOther,2) @ 1,1 SAY "Для фильтрации определите код раздела F3 или ничего по всем" GET cCodGroup VALI IF(Empty(cCodGroup),TRUE,Eval(bCodGroup,cCodGroup)) @ 2,1 SAY "Непрерывный набор букв из любого места наименования" GET cfName PICT "@!" @ 3,1 SAY "1-отражать только заказанные товары, 2-не заказанные, 3-все " GET nfZak PICT "9" READ fDeact( cOldCol ) AP__INPUT // Если все значения пустые, то снимаю фильтр cfName := Alltrim(cfName) IF Empty(cCodGroup) .AND. Empty(cfName) .AND. nfZak <> 1 .AND. nfZak <> 2 SET FILTER TO ELSE // Устанавливаю SET FILTER TO IF(Empty(cCodGroup),TRUE,codGroup==cCodGroup) .AND.; IF(Empty(cfName),TRUE,At(Upper(cfName),Upper(name))>=1) .AND.; IF(nfZak==1,qtyPak>0.OR.qtyLitr>0,IF(nfZak==2,qtyPak<=0.AND.qtyLitr<=0,TRUE)) ENDI DbGoBottom() DbGoTop() RETU [/pre]

Softlog86: Для простоты я обобщил как "геометрические" ..... Если взять что-то сложнее куба , например , такую автозапчасть как шкив генератора : A=Посадочный диаметр B=Внешний диаметр C=Общая высота D=Вынос E=Число ручьёв ремня .... В общем-то и задумывается как поиск по Метрическим и иным параметрам ... Пока готовлю разумный план реализации :) Должно быть как-бы универсальным - подставляй любой файл-набитую базу и получай технический поисковик по параметрам :) PS: Вот-бы что и с GET-ми придумать толковое ...... Формировать форму ввода данных на основе того самого файла DBF где и лежат эти самые искомые (фильтруемые) данные

Andrey: AndreyZh пишет: но ... нашел и фильтрацию... крайне медленная операция по сети Сделай условную индексацию (Клипер 5.3) и будет быстрее в разы !

petr707: Сколько записей в DBF ? Какой набор значений по каждой колонке ? Если не очень много - может проще загнать в Excel(или Calc из OpenOffice) ? А там есть автофильтр, и все Get's -будут в виде комбобоксов

Vlad04: Я подобные выборки делаю условной индексацией или запросами (ADS). Фильтрация приемлима только для небольших баз.Если после установки фильтра ты еще просматриваешь результат и найдено всего несколько записей, тогда вообще "вешалка".

Softlog86: Записей может быть до 3-5 тыс . Это максимум . Просьба EXCELL вообще не вспоминать . Всё-ж CLIPPER для того и используем :)

petr707: Для 5 тысяч - без хлопот со сложными фильтрами и индексами- быстро идет копирование общей таблицы по условию - функция от параметров во временную локальную таблицу, открываемую заново и экслюзивно после каждого копирования ( если есть возможность применения локальных таблиц) .. copy to (tmp) for get_size(a1,b1,a2,b2,..)

Pasha: 3-5 тыс.записей - это детский размер. Я думал, раз в 100 больше, 300-500 тыс. В таком простом случае для поиска по 4-м параметрам (геометрическим размерам) надо сделать 4 постоянных индекса по каждому из "размеров", и для поиска использовать любой из них. Такой поиск будет заведомо эффективнее, чем простой фильтр, который предполагает выборку из всей таблицы. А условный индекс, который предлагают Андрей и Влад, ничем не лучше простого фильтра. Для создания условного индекса, а для каждой операции поиска надо создавать свой условный индекс, необходима такая же выборка всех записей таблицы. Поиск по условному индексу будет очень быстрый, но его создание плюс поиск по нему ничем не лучше простого фильтра. А если учесть, что для каждой операции поиска придется создавать свой временный условный индекс, то такой способ заведомо хуже, чем простой тупой фильтр. Так что не стоит предлагать в качестве решения этот метод.

Andrey: Pasha пишет: А условный индекс, который предлагают Андрей и Влад, ничем не лучше простого фильтра. Для создания условного индекса, а для каждой операции поиска надо создавать свой условный индекс, необходима такая же выборка всех записей таблицы. Поиск по условному индексу будет очень быстрый, но его создание плюс поиск по нему ничем не лучше простого фильтра. А если учесть, что для каждой операции поиска придется создавать свой временный условный индекс, то такой способ заведомо хуже, чем простой тупой фильтр. Паша, ты не прав. Я имел ввиду, что условный индекс БУДЕТ строиться по уже индексированному полю базы (можно допустим по А). Это будет быстро и просто по написанию кода. Сразу после индекса выводит TBROWSE(). Тем более будет всего 3-5 тыс.записей .... Я таким вариантом пользовался еще с 1997 года, да и на хХарборе пока оставил. А на больший размер, конечно твой вариант будет правильней !

Pasha: Andrey пишет: Паша, ты не прав. Я имел ввиду, что условный индекс БУДЕТ строиться по уже индексированному полю базы (можно допустим по А). Это будет быстро и просто по написанию кода. Сразу после индекса выводит TBROWSE(). Тем более будет всего 3-5 тыс.записей .... Я таким вариантом пользовался еще с 1997 года, да и на хХарборе пока оставил. А на больший размер, конечно твой вариант будет правильней ! Это с использованием опции usecurrent, что ли ? Допустим, имеется постоянный индекс по полю A. А условный индекс будет по какому полю, и что в условии for ? Условие while, record используется ? Условный индекс ты предлагаешь создавать для каждой операции поиска, а затем удаляешь его ?

Andrey: Pasha пишет: Допустим, имеется постоянный индекс по полю A. А условный индекс будет по какому полю, и что в условии for ? Условие while, record используется ? Можно условие for использовать.... DBSELECT(1) // переключаемся на открытый индекс A // далее условный индекс для Клипера 5.3 INDEX ON &cIndexTo TAG "ONE" TO (cTempFileIndex) ; EVAL MES_BARW( aBeg, IIF( lFlag, RECNO(), ORDKEYNO() ), nKolRecords ) ; EVERY nKolRecords / 10 FOR &cFilter ADDITIVE ORDSETFOCUS( "ONE" ) DBSETORDER(2) где MES_BARW() - моя функция бегунка и cFilter - как предложил PSP В клипере по условная индексация по уже открытому индексу вход. в условин отбора - очень ШУСТРО строится, даже по сети. А SET FILTER TO по условию индексного файла отрабатывает лучше чем в Харборе. Просто в Клипере есть(включена) оптимизация для SET FILTER, в Харборе такого нет ! Я такую конструкцию использую и сейчас, хотя улучшил для Харбора по твоей рекомендации (см. условную индексацию здесь на форуме) ! Pasha пишет: Условный индекс ты предлагаешь создавать для каждой операции поиска, а затем удаляешь его ? Да, именно так.

Pasha: Andrey пишет: В клипере по условная индексация по уже открытому индексу вход. в условин отбора - очень ШУСТРО строится, даже по сети. А SET FILTER TO по условию индексного файла отрабатывает лучше чем в Харборе. Просто в Клипере есть(включена) оптимизация для SET FILTER, в Харборе такого нет ! Для создания индекса таким образом необходима выборка всех записей файла, от первой и до последней. Чудес не бывает. И чем это лучше обычной выборки с фильтром ? Ничем не лучше, а наоборот хуже, поскольку помимо выборки выполняется формирование индекса, т.е. построение бинарного дерева и его запись на диск. А если учесть, что такой индекс одноразовый, такой способ совсем уж абсурдный. А что за оптимизация set filter в клиппере ? Какой ее механизм ? Как вообще set filter можно оптимизировать ? Что это за фантастика ?

Andrey: Pasha пишет: А что за оптимизация set filter в клиппере ? Какой ее механизм ? Как вообще set filter можно оптимизировать ? Что это за фантастика ? Ну я с этим сталкивался еще при переходе на хХарбор. SET FILTER (для CDX) в Клипере 5.3 даже по сети работает на несколько порядков быстрей чем в хХарборе. Там по документации описана вкл/отк. ОПТИМИЗАЦИИ запросов. Это не фантастика. В клипере 5.2 такого не было, это появилось только в 5.3 Мне потом пришлось переделывать под хХарбор логику по выборке из базы, т.е. в Клипере 5.3 я делал SET FILTER TO (условие) - и получал даже по сети, очень быстро данные. Я на Клипере 5.3 долго сидел с 1994 года. Есть даже примеры по этим выборкам. Если надо, поищу.

Pasha: Andrey пишет: Ну я с этим сталкивался еще при переходе на хХарбор. SET FILTER (для CDX) в Клипере 5.3 даже по сети работает на несколько порядков быстрей чем в хХарборе. Там по документации описана вкл/отк. ОПТИМИЗАЦИИ запросов. Это не фантастика. Мне потом пришлось переделывать под хХарбор логику по выборке из базы, т.е. в Клипере 5.3 я делал SET FILTER TO (условие) - и получал даже по сети, очень быстро данные. Я на Клипере 5.3 долго сидел с 1994 года. Есть даже примеры по этим выборкам. Если надо, поищу. По-видимому, имеется в виду команда set optimize. Оптимизация при этом сводится к использованию открытого индекса при выборке по фильтру, то есть это просто неявное использование scope. Но ничего не мешает явно использовать scope, если в выражении фильтра присутствуют индексные поля. Наоборот, это делать крайне необходимо, если хочется получить быстрый фильтр. Но опять таки, временный условный индекс здесь ни каким боком не прицепишь.

Andrey: Pasha пишет: Но опять таки, временный условный индекс здесь ни каким боком не прицепишь. Ну не буду спорть. На данную задачу это может и не нужно.... Я просто предложил как вариант.

Pasha: Здесь есть еще такой ньюанс При построении индекса индексный доступ к файлу не используется, т.е при индексации неявно устанавливается set order to 0. При этом для выборки записей для индексации не надо блокировать индекс, и выборка по сети выполняется намного быстрее. Чтобы достигнуть такой же производительности при выборке с фильтром, необходимо также задать: set order to 0 или dbOrderInfo(DBOI_READLOCK,,, .t.) а после выборки: dbOrderInfo(DBOI_READLOCK,,, .f.) это конечно команды харбора При индексации еще для чтения записей используется буфер 64К. Но не это дает такую высокую скорость выборки, так как буфер ОС все равно используется, а именно отсутствие необходимости блокировать индекс.

ММК: Pasha пишет: Поиск по условному индексу будет очень быстрый, но его создание плюс поиск по нему ничем не лучше простого фильтра. А если учесть, что для каждой операции поиска придется создавать свой временный условный индекс, то такой способ заведомо хуже, чем простой тупой фильтр. Так что не стоит предлагать в качестве решения этот метод. Пользуюсь именно этим методом :) Берем базу с разными полями (числ., стр., дата...) .Хочется в ней сделать какую-то выборку, Причем сразу может быть и не ясны конкретные "рамки" . Другими словами ставим один "фильтр" потом по рузультату второй и т.д. ( кстати , временный условный индекс создается только раз, далее в него просто добавляются условия ) Вот на картинке бровс с базой с выбранным индексом по коду. Можно "щелкнуть" по наменованию -индекс сменится. Теперь выбираем любое интересующее нас поле и по правой клавише мыши выбираем условие выборки .К примеру больше нуля. Вот один фильтр :) Теперь повторяем операцию и берез значение меньше 10. Вот уже второй ... Становимся на другое поле ... и т.д. Все наглядно и быстро Приблизительно так... mykey:=indexkey() MOldOrd:=ordname() MOldBag:=ORDBAGNAME() If временный индекс не создан index on &mykey to tsmy_idx for !deleted() CUSTOM ADDITIVE Endif set order to tag (MOldBag) ....... do case case valtype(wot)=='C'//.and.::lDostext myblock:=&('{||iif('+bloo+alltrim(znak)+'"'+alltrim(wot)+'",ORDKEYADD("TSMY_IDX","tsmy_idx.cdx",'+mykey+'),)}') case valtype(wot)=='N' ........ case valtype(wot)=='D' ........ endcase dbeval(myblock) SET ORDER TO TAG tsmy_idx Go top http://shot.qip.ru/008r16-38walgHwn/

Andrey: ММК пишет: Пользуюсь именно этим методом :) Берем базу с разными полями (числ., стр., дата...) .Хочется в ней сделать какую-то выборку, Причем сразу может быть и не ясны конкретные "рамки" . Другими словами ставим один "фильтр" потом по рузультату второй и т.д. Я тоже пользуюсь этим методом с 1996 года ! Но в данном случае имеется всего 4 поля. И Пашин метод лучше для этого варианта. Красивая картинка. На чем сделано: МиниГуи или FiveWin ?

Pasha: ММК пишет: Пользуюсь именно этим методом :) Берем базу с разными полями (числ., стр., дата...) .Хочется в ней сделать какую-то выборку, Причем сразу может быть и не ясны конкретные "рамки" . Другими словами ставим один "фильтр" потом по рузультату второй и т.д. ( кстати , временный условный индекс создается только раз, далее в него просто добавляются условия ) Вот на картинке бровс с базой с выбранным индексом по коду. Можно "щелкнуть" по наменованию -индекс сменится. Теперь выбираем любое интересующее нас поле и по правой клавише мыши выбираем условие выборки .К примеру больше нуля. Вот один фильтр :) Теперь повторяем операцию и берез значение меньше 10. Вот уже второй ... Становимся на другое поле ... и т.д. Все наглядно и быстро Приблизительно так... Это все-таки немного другое, custom-индекс это не тоже самое, что индекс с условием for. Но зато в коде наглядно видно, как строится такой индекс: посредством dbeval, то есть выборки всех до единой записей таблицы. Такой способ быстрым быть не может, наоборот, это самый медленный способ из всех возможных. Единственное его преимущество - это то, что после построения такого индекса записи, которые присутствуют в индексе, будут выбираться быстро. Преимущество custom-индекса перед индексом с for то, что при построении второго выполняется сортировка ключей, а первого - ключи просто добавляются в индекс, что немного быстрее.

ММК: Pasha пишет: Это все-таки немного другое, custom-индекс это не тоже самое, что индекс с условием for. Но зато в коде наглядно видно, как строится такой индекс: посредством dbeval, то есть выборки всех до единой записей таблицы. Такой способ быстрым быть не может, наоборот, это самый медленный способ из всех возможных. Именно ,что другое :)Если бы речь шла о статике , то да. Мы ведь не сравниваем скорости отдельных операций , а ищем удобное решение для конкретной задачи . Может он и не самый быстрий , но уж точно не самый медленный. Каждый раз выборка идет в уже отобранной базе . Мы же не говорим о еденичной операции :)) Andrey пишет: Но в данном случае имеется всего 4 поля. И Пашин метод лучше для этого варианта. Может и лучше :) Смысл в том ,что строится один индекс , а не четыре. И не имеет значение сколько полей будет использоваться для выборки. Если я правильно понял Пашино предложение , чем больше полей тем больше индексов надо построить , а потом еще на них наложить те или иные выборки... Пользуюсь я и тем и другим способом ( скопе , индекс , фильтр ) , но при работе с таблицей , которая должна быть наглядной и выборки НЕ ПРЕДСКАЗУЕМЫ это самый оптимальный вариант :) Хотя ,если что-то еще придумаете будет очень интересно :)) Да и не надо забывать ,что речь идет о достаточно маленьких базах. Написано на FWH

Andrey: ММК пишет: Да и не надо забывать ,что речь идет о достаточно маленьких базах. Это уж точно. Еще это и более простой способ написания кода под такие задачки !

Pasha: ММК пишет: Именно ,что другое :)Если бы речь шла о статике , то да. Мы ведь не сравниваем скорости отдельных операций , а ищем удобное решение для конкретной задачи . Может он и не самый быстрий , но уж точно не самый медленный. Каждый раз выборка идет в уже отобранной базе . Мы же не говорим о еденичной операции :)) Маленький совет: перед dbeval делать dbSetOrder(0) Тогда выборка записей будет последовательной, что немного быстрее, чем с использованием индекса. А если выборка идет из файла, открытого по сети - то намного быстрее, так как не выполняется блокировка индекса, которая может замедлить выборку в разы. А насчет сортировки в custom индексе я оказался неправ - там тоже сортировка делается.

ММК: Pasha пишет: Маленький совет: перед dbeval делать dbSetOrder(0) За маленький совет -большое спасибо! :)))



полная версия страницы