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

Программисту на заметку:
Отбор элементов справочника по строковым реквизитам через прямой запрос. Универсально, для 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 — затем клавишу «Я» и при зажатой клавишу «Я» набирает последние цифры штрихкода  — справочник мгновенно фильтруется. При отжатии клавиши «Я» фильтр сбрасывается, а курсор активизируется на элемент, который был активен при фильтре — мои юзеры просто в восторге… 🙂

 

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

 

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

 

 

31 Comments

  1. Noy

    P.S. В базах DBF будет работать только в разделенном режиме.

    Reply
  2. Ёпрст

    (1) при помощи правки dbeng32 от hogik работает в любом…

    Reply
  3. Ёпрст

    +2 всё это конечно хорошо, но вот решение, имхо , получшее:

    http://www.1cpp.ru/forum/YaBB.p

    Reply
  4. Noy

    (3) Не получшее, а лучше просто в разы!

    Ясень пень, что моя маленькая заготовка с ней не сравниться, но как обучающий материал пойдет.

    Reply
  5. Ёпрст

    (4) ну ясно…и это , к (2) тоже приглядись, если что на будующее…

    Reply
  6. Ёпрст
  7. Noy

    (5,6) Спасибо.

    Reply
  8. rasswet

    плюсанул за идею, сам видимо пользоваться не буду

    Reply
  9. anics

    Что с этим делать?

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

    {C:DOCUMENTS AND SETTINGSАДМИНИСТРАТОРРАБОЧИЙ СТОЛFN_FINDSPR.ERT(23)}: Неудачная попытка создания объекта (MetaInfoClasses)

    Reply
  10. Ёпрст

    (9) загрузить ВК 1cpp.dll, для начала.

    Reply
  11. anics

    1cpp.dll загружается, ошибка остается

    Reply
  12. Ёпрст

    (11) версия 1сpp.dll какая ?

    Reply
  13. anics

    2.0.3.1

    Reply
  14. anics

    с 2.5.0.7 то же самое

    Reply
  15. Ёпрст

    (14) http://www.1cpp.ru/images/3/32/Icpp-latest.rar

    а с этой ?

    А вк точно загружена ?

    Reply
  16. anics

    и с 3.0.1.22 не работает. Вк загружается, в примере же прописывется ее вызов.

    Reply
  17. Ёпрст

    (16) Другие ВК есть?

    Reply
  18. Ёпрст

    (16) На закладке в 1с-предприятие, в Помощь о программе, появилась вкладка с ВК ?

    Reply
  19. anics

    Заработала. Надо было Вк вызывать не в процедуре ПриОткрытии() обработки,

    а в процедуре ПриНачалеРаботыСистемы().

    Reply
  20. Ёпрст

    (19) это без разницы… можно хоть в Табло в самом предприятии написать строчку ЗагрузитьВнешнююКомпоненту(«1cpp.dll») …

    Reply
  21. anton.fly7

    Привет!

    только начинаю упражняться с прямыми запросами…

    скажите, в этой строке

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

    что должно быть написано? я так понел что косяк какой то…

    Reply
  22. anton.fly7

    разобрался 😳

    Reply
  23. anton.fly7

    почему то не ищет по наименованию по русским буквам… ❓

    Reply
  24. Noy

    (23) у меня ищет…

    база скульная? функцию покажи…

    Reply
  25. Noy

    (23) Вижу на мисте уже ответили 😉

    Reply
  26. anton.fly7

    опять разобрался…

    передавал на поиск маленькими буквами, а в запросе приводися к большим буквам

    Reply
  27. anton.fly7

    «UPPER(» + ТекПоле + «) Like ‘%’ + :Стр» + Строка(i) + » + ‘%'»

    Reply
  28. Noy

    «UPPER(» + ТекПоле + «) Like ‘%'» + ВРЕГ(Строка(i)) + «‘%'»

    Reply
  29. selesta

    вещь супер, на 600 тыс. справочнике результат на 2 секунде

    спасибо за простоту и универсальность!

    Reply
  30. selesta

    добавлю еще — не работает поиск с апострофом (одинарной кавычкой)

    нужно заменить ее на 2

    ИскомаяСтрока = СтрЗаменить(ИскомаяСтрока,»‘»,»»»);

    Reply
  31. Noy

    (30) никто не совершенен. Баги в ПО будут всегда 🙂

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *