gifts2017

Универсальная функция отбора в справочниках

Опубликовал Алексей Плутенко (Noy) в раздел Программирование - Инструментарий

Программисту на заметку:
Отбор элементов справочника по строковым реквизитам через прямой запрос. Универсально, для SQL и DBF. Работает очень быстро!

Для 7.7

Это скорее маленькая статья, чем обработка, но в статьях не нашел как прикреплять файл - поэтому размещаю в обработках.

 

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

 

 


 

//Функция возвращает первые (все) элементы справочника, найденные по подстроке, в списоке значений

//Справочник = Идетинтификатор справочника (строка)

//ПолеПоиска = Реквизиты, по которым делать поиск (строка, разделенная запятыми)

//Метод = Метод поиска (1-поиск по вхождению, 2-поиск по первым символам, 3-поиск по последним символам)

//Искомая строка = Что ищем (строка)

//КвоЭлементов = кол-во, указывающий сколько элементов возвращать (10 - вернуть первые 10 элементов, удовлетворяющий условию, 0 - вернуть все элементы)

Функция глФильтрСправочника(Справочник,ПолеПоиска="",Метод=1,Знач ИскомаяСтрока="", КвоЭлементов=0,спРезультатов="") Экспорт

Если ТипЗначенияСтр(спРезультатов)<>"СписокЗначений" тогда спРезультатов=СоздатьОбъект("СписокЗначений");КонецЕсли;

Если ПустоеЗначение(ПолеПоиска)+ПустоеЗначение(ИскомаяСтрока)<>0 Тогда Возврат спРезультатов; КонецЕсли;

   спПолейПоиска=СоздатьОбъект("СписокЗначений");

   спПолейПоиска.ИзСтрокиСРазделителями(""""+СтрЗаменить(ПолеПоиска,",",""",""")+"""");

для х=1 по спПолейПоиска.РазмерСписка() Цикл

Если Врег(спПолейПоиска.ПолучитьЗначение(х))=Врег("Наименование") Тогда

спПолейПоиска.УстановитьЗначение(х,"спр.DESCR");

ИначеЕсли Врег(ПолеПоиска)=Врег("Код") Тогда

спПолейПоиска.УстановитьЗначение(х,"спр.Code");

Иначе

спПолейПоиска.УстановитьЗначение(х,"$Справочник."+Справочник+"."+спПолейПоиска.ПолучитьЗначение(х));

КонецЕсли;

КонецЦикла;

   МИК=СоздатьОбъект("MetaInfoClasses");

Если МИК.ЭтоSQL_Версия()=1 тогда

НоЛок=" (NOLOCK)";

Запрос = СоздатьОбъект("ODBCRecordset");

   Иначе

Если МонопольныйРежим()=1 Тогда

Возврат спРезультатов;

КонецЕсли;

НоЛок="";

База = СоздатьОбъект("OLEDBData");

Соединение ="

|Provider=VFPOLEDB.1;

|Data Source=" + КаталогИБ() + ";

|Mode=Read;

|";

Рез = База.Соединение(Соединение);

Запрос = База.СоздатьКоманду();

КонецЕсли;

   ИскомаяСтрока=Врег(СокрЛП(ИскомаяСтрока));

   ТекстЗапроса = "

|SELECT"+?(КвоЭлементов=0,""," Top "+КвоЭлементов)+"

| спр.ID as [Элемент $Справочник."+Справочник+"]

|FROM

| $Справочник."+Справочник+" as спр"+НоЛок+"

|Where

|"+?(Метаданные.Справочник(Справочник).КоличествоУровней>1,"спр.ISFOLDER=2 AND","");

для х=1 по спПолейПоиска.РазмерСписка() Цикл

ТекПоле=спПолейПоиска.ПолучитьЗначение(х);

Если Метод=1 Тогда

ТекстЗапроса=ТекстЗапроса+"

|UPPER("+ТекПоле+") Like &apos;%&apos; + :Стр + &apos;%&apos;";

ИначеЕсли Метод=2 Тогда

ТекстЗапроса=ТекстЗапроса+"

|UPPER(Left(LTRIM("+ТекПоле+"),"+СтрДлина(ИскомаяСтрока)+"))=:Стр";

ИначеЕсли Метод=3 Тогда

ТекстЗапроса=ТекстЗапроса+"

|UPPER(RIGHT(RTRIM("+ТекПоле+"),"+СтрДлина(ИскомаяСтрока)+"))=:Стр";

КонецЕсли;

Если х<спПолейПоиска.РазмерСписка() тогда ТекстЗапроса=ТекстЗапроса+" OR"; КонецЕсли;

КонецЦикла;

ТекстЗапроса=ТекстЗапроса+"

|ORDER BY "+спПолейПоиска.ПолучитьЗначение(1);

   Запрос.УстановитьТекстовыйПараметр("Стр", ИскомаяСтрока);

Если МИК.ЭтоSQL_Версия()=1 тогда

Запрос.ВыполнитьИнструкцию(ТекстЗапроса,спРезультатов);

   Иначе

ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);

ТЗ.Выгрузить(спРезультатов,,,"Элемент");

КонецЕсли;

Возврат спРезультатов;

КонецФункции

 

 

 

 


 

 

 

Требует 1С++ (http://www.1cpp.ru/index.php/Download) - обязательно.

И Microsoft OLE DB Provider для DBF баз (http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=e1a87d8f-2d58-491f-a0fa-95a3289c5fd4).

Как внедрить:

скачать 1С++, компоненту положить в каталог ИБ (или программы)

В процедуре ПриНачалеРаботыСистемы прописать

Попытка

        ЗагрузитьВнешнююКомпоненту(КаталогИБ()+"1CPP.dll");

Исключение
        Сообщить("Ошибка при загрузке ВК 1CPP.dll");
КонецПопытки;

 

 

Добавить в глобальный модуль указанную выше функцию.

А дальше можно использовать так:

Простейший пример: На форме списка справочника товаров/клиентов добавлем поле ввода "ФильтрСтр" - тип строка и две кнопки - "Фильтр()" и "ОтменаФильтра()"

В модуль формы добавлем процедуры:

Процедура Фильтр()

ИерархическийСписок(0);

ИспользоватьСписокЭлементов(глФильтрСправочника(Вид(),"Наименование,ПолнНаименование",1,ФильтрСтр));

Форма.Обновить();

КонецПроцедуры

Процедура ОтменаФильтра()

ИспользоватьСписокЭлементов();

КонецПроцедуры

 

Это простейший вариант использования данной функции.

Есть еще вариант - в отчеты по продажам/остаткам и тп - добавляем такое же поле ввода, а в запрос добавлем условие

что-то типа: Условие (Товар в спСтрФильтр)

где спСтрФильтр=глФильтрСправочника("Номенклатура","Наименование,ПолнНаименование",1,ФильтрСтр)

в итоге будем иметь возможность строить отчеты по всем товарам, где содержится например слово "шампунь"...

 

А если еще прикрутить формекс - то можно отлавливать нажатия клавиш прямо в форме списка справочника и фильтровать на лету.

Например у себя использую такой код в форме списка (Внимание, код не универсален - "причесывайте" под себя):

Перем ПоискПоШтрихКоду, ВернутьИерархию, РежимПодбора;

Процедура ПриНажатииКнопкиКлавиатуры(КодКлавиши,Alt,Shift,Ctrl,Символ,ФСО)
    Если (Shift=1) и (Alt+Ctrl=0) и (КодКлавиши=90) Тогда
        РежимПодбора=1;
        ФСО=0;
        Возврат;
    КонецЕсли;
    Если РежимПодбора=1 Тогда
        Если КодКлавиши=90 Тогда
            ФСО=0;
            Возврат;
        КонецЕсли;
        Если (КодКлавиши<58) и (КодКлавиши>47) тогда
            ФСО=0;
            ПоискПоШтрихКоду=ПоискПоШтрихКоду+Симв(КодКлавиши);
            Если ИерархическийСписок()=1 тогда
                ВернутьИерархию=1;
                ИерархическийСписок(0);
            КонецЕсли;
            ИспользоватьСписокЭлементов(глФильтрСправочника("ТМЦ","ШтрихКод,КодЯщика",3,ПоискПоШтрихКоду,50)); Форма.Обновить();
        ИначеЕсли (КодКлавиши<106) и (КодКлавиши>95) тогда
            ФСО=0;
            Если ИерархическийСписок()=1 тогда
                ВернутьИерархию=1;
                ИерархическийСписок(0);
            КонецЕсли;
            ПоискПоШтрихКоду=ПоискПоШтрихКоду+Симв(КодКлавиши-48);
            ИспользоватьСписокЭлементов(глФильтрСправочника("ТМЦ","ШтрихКод,КодЯщика",3,ПоискПоШтрихКоду,100)); Форма.Обновить();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Процедура ПриОтжатииКнопкиКлавиатуры(КодКлавиши,Alt,Shift,Ctrl,Символ,ФСО)
    Если (КодКлавиши=90) и (РежимПодбора=1) Тогда
        РежимПодбора=0;
        ТекЭлемент=ТекущийЭлемент();
        ПоискПоШтрихКоду="";
        ИспользоватьСписокЭлементов();
        Если ВернутьИерархию=1 тогда ИерархическийСписок(1); КонецЕсли;
        АктивизироватьОбъект(ТекЭлемент);
    КонецЕсли;   
КонецПроцедуры

В моем случае пользователь Нажимает Shift - затем клавишу "Я" и при зажатой клавишу "Я" набирает последние цифры штрихкода  - справочник мгновенно фильтруется. При отжатии клавиши "Я" фильтр сбрасывается, а курсор активизируется на элемент, который был активен при фильтре - мои юзеры просто в восторге... :)

 

В качестве демонстрации прикладываю обработку, демонстрирующую работу функции.

 

Статья расчитана в первую очередь на тех, кто хочет быстро попробовать - что же это за зверь - "прямой запрос".

 

 

Скачать файлы

Наименование Файл Версия Размер
Отбор по справочнику 323
.1243244290 40,00Kb
24.12.14
323
.1243244290 40,00Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Алексей Плутенко (Noy) 25.05.09 14:03
P.S. В базах DBF будет работать только в разделенном режиме.
2. Епрст (Ёпрст) 25.05.09 15:00
(1) при помощи правки dbeng32 от hogik работает в любом...
3. Епрст (Ёпрст) 25.05.09 15:02
+2 всё это конечно хорошо, но вот решение, имхо , получшее:
http://www.1cpp.ru/forum/YaBB.pl?num=1211491690
4. Алексей Плутенко (Noy) 25.05.09 15:07
(3) Не получшее, а лучше просто в разы!
Ясень пень, что моя маленькая заготовка с ней не сравниться, но как обучающий материал пойдет.
5. Епрст (Ёпрст) 25.05.09 15:14
(4) ну ясно...и это , к (2) тоже приглядись, если что на будующее...

7. Алексей Плутенко (Noy) 25.05.09 15:20
8. rasswet (rasswet) 27.05.09 08:54
плюсанул за идею, сам видимо пользоваться не буду
9. Anics (anics) 27.05.09 10:21
Что с этим делать?

МИК=СоздатьОбъект("MetaInfoClasses");
{C:\DOCUMENTS AND SETTINGS\АДМИНИСТРАТОР\РАБОЧИЙ СТОЛ\FN_FINDSPR.ERT(23)}: Неудачная попытка создания объекта (MetaInfoClasses)
10. Епрст (Ёпрст) 27.05.09 10:25
(9) загрузить ВК 1cpp.dll, для начала.
11. Anics (anics) 27.05.09 10:32
1cpp.dll загружается, ошибка остается
12. Епрст (Ёпрст) 27.05.09 10:33
14. Anics (anics) 27.05.09 10:47
15. Епрст (Ёпрст) 27.05.09 10:59
16. Anics (anics) 27.05.09 11:07
и с 3.0.1.22 не работает. Вк загружается, в примере же прописывется ее вызов.
17. Епрст (Ёпрст) 27.05.09 11:12
18. Епрст (Ёпрст) 27.05.09 11:14
(16) На закладке в 1с-предприятие, в Помощь о программе, появилась вкладка с ВК ?
19. Anics (anics) 27.05.09 11:21
Заработала. Надо было Вк вызывать не в процедуре ПриОткрытии() обработки,
а в процедуре ПриНачалеРаботыСистемы().
20. Епрст (Ёпрст) 27.05.09 11:24
(19) это без разницы... можно хоть в Табло в самом предприятии написать строчку ЗагрузитьВнешнююКомпоненту("1cpp.dll") ...
21. Антон (anton.fly7) 04.10.09 13:56
Привет!
только начинаю упражняться с прямыми запросами...
скажите, в этой строке

|UPPER("+ТекПоле+") Like '%' + :Стр + '%'";

что должно быть написано? я так понел что косяк какой то...
22. Антон (anton.fly7) 04.10.09 14:03
23. Антон (anton.fly7) 06.10.09 14:37
почему то не ищет по наименованию по русским буквам... :?:
24. Алексей Плутенко (Noy) 06.10.09 15:10
(23) у меня ищет...
база скульная? функцию покажи...
25. Алексей Плутенко (Noy) 06.10.09 15:15
(23) Вижу на мисте уже ответили ;)
26. Антон (anton.fly7) 06.10.09 15:17
опять разобрался...
передавал на поиск маленькими буквами, а в запросе приводися к большим буквам
27. Антон (anton.fly7) 06.10.09 15:18
"UPPER(" + ТекПоле + ") Like '%' + :Стр" + Строка(i) + " + '%'"
28. Алексей Плутенко (Noy) 06.10.09 15:25
"UPPER(" + ТекПоле + ") Like '%'" + ВРЕГ(Строка(i)) + "'%'"
29. selesta (selesta) 18.06.12 01:47
вещь супер, на 600 тыс. справочнике результат на 2 секунде
спасибо за простоту и универсальность!
30. selesta (selesta) 03.07.12 14:04
добавлю еще - не работает поиск с апострофом (одинарной кавычкой)
нужно заменить ее на 2
ИскомаяСтрока = СтрЗаменить(ИскомаяСтрока,"'","''");
31. Алексей Плутенко (Noy) 03.07.12 14:30
(30) никто не совершенен. Баги в ПО будут всегда :)