Книга знаний

1С:Предприятие / Приемы программирования / Внешние компоненты

Множественный отбор в журналах и справочниках 7.7 заменой запросов SQL

Разработка позволяет модифицировать SQL-запросы 1С:Предприятие, в частности, с целью установления типичных для SQL-баз отборов в журналах и справочниках сразу по нескольким реквизитам. Кроме того, разработка реализует быстрый подбор в справочниках по первым буквам наименования.Автор статьи: romix | Редакторы: ASV
Последняя редакция №10 от 19.12.11 | История
URL: http://kb.mista.ru/article.php?id=361

Ключевые слова: SQL, ODBC32.dll, подмена, отбор, журнал, справочник, реквизит, одновременно, множественный, документ


Файл для скачивания:
http://x-romix.narod.ru/vk_hook1C.rar (81К, скачивать левой кнопкой мыши).
Приложены исходные тексты внешней компоненты (компилятор - Delphi 6).

Разработка протестирована для 1С:Предприятие 7.7, 25 релиз.

(Релиз для Windows Server 2008: http://infostart.ru/public/83504/ от maxpiter и Old_Joe)

Приложен тестовый пример конфигурации, который надо восстановить в SQL (не DBF!) - базу
из меню "Администрирование" - "Загрузить данные" в режиме Конфигуратора 1С:Предприятие 7.7.

Пример демонстрирует множественный отбор в журнале документов (по "общим реквизитам": Контрагент, Автор и Товар), а также показ только "не помеченных на удаление". У этих реквизитов установлена галочка "отбор", чтобы они попали в таблицу _1SJOURN.

Кроме того, при попытке выполнить выбор из справочника, система запрашивает первые буквы наименования. Отобразит в форме списка справочника только элементы по этим буквам (% - метасимвол, как в предложении LIKE языка запросов SQL).

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

Штатные возможности по отбору в журналах



Используйте метод:

УстановитьОтбор(<ИмяОтбора>,<ЗначениеОтбора>)


или

УстановитьОтбор(<ВидДокумента>)


чтобы выполнить отбор в журнале по одному какому-нибудь признаку. В такой ситуации нет необходимости использовать внешнюю компоненту, достаточно воспользоваться штатными возможностями 1С:Предприятие.

Даже если нужен отбор по двум или большему числу признаков, рассмотрите вопрос о том, чтобы использовать комбинированный реквизит, составленный из нескольких признаков - это может быть более простым способом, чем перехватывать и изменять SQL запросы.

В качестве реализации такого механизма можно предложить справочник, в котором наименование содержит текстовое представление сразу нескольких (двух, трех или более) реквизитов, и есть сами реквизиты. Текстовое представление можно получить, например, штатным механизмом 1С ЗначениеВСтрокуВнутр() и вырезать нужные (определяющие сам объект) части строки.

Рассматривайте описанный ниже способ с подменой запросов как средство отчасти черной магии, к которому лучше прибегать только в тех ситуациях, когда штатные или близкие к стандартным механизмы 1С и приемы программирования уже были исчерпаны.

Установка внешней компоненты



В настоящей версии не требуются патчи для замены библиотеки ODBC32.dll - все делает внешняя компонента. Вот код для ее инициализации из глобального модуля 1С:

///////////////////////////////////////////////////////////////////////
//Предопределенная процедура 1С
Процедура ПриНачалеРаботыСистемы()
    
    каталог="..\";//надкаталог
    ЗагрузитьВнешнююКомпоненту(каталог+"vk_Hook1C.dll"); 
    vk_hook=СоздатьОбъект("Addin.vk_Hook1C");
    vk_hook.ПерехватSQLPrepare();
    //vk_hook.ПоказыватьSQL=1;
КонецПроцедуры    // ПриНачалеРаботыСистемы


Свойство ПоказыватьSQL, будучи установленным в 1, позволяет увидеть проходящие через систему SQL-запросы в функции SQLPrepareA.

Как увидеть запросы?



Включите параметр

vk_hook.ПоказыватьSQL=1;

(см. выше).

Запросы приходят в виде события.

///////////////////////////////////////////////////////////////////////
//Предопределенная процедура 1С
Процедура ОбработкаВнешнегоСобытия(Источник,СобытиеДанные)
        Сообщить(""+Источник+" "+Событие+" "+Данные);
КонецПроцедуры    // ПриНачалеРаботыСистемы




Перевод объектов в формат SQL


Чтобы использовать в запросах конкретные значения для объектов (например, ссылки на элементы справочников, я использую следующую процедуру):

///////////////////////////////////////////////////////////////////////
//Преобразует объект в идентификатор, пригодный для SQL
Функция ПолучитьИД(прм_Объект)
    стр=СокрЛП(ЗначениеВСтрокуВнутр(прм_Объект));
    стр=Сред(стр,2,СтрДлина(стр)-2); //Убираем {}
    сз=СоздатьОбъект("СписокЗначений");
    сз.ИзСтрокиСРазделителями(стр);
    стр=сз.ПолучитьЗначение(7);
    иб=Прав(стр,3);
    стр=Лев(стр, СтрДлина(стр)-3); //Отрезаем последние 3 символа
    стр=_IdToStr(стр);
    стр=стр+иб;
    Пока СтрДлина(стр)<9 Цикл //Дополняем слева пробелами
        стр=" "+стр;
    КонецЦикла;
    Возврат стр;
    
КонецФункции    // ПолучитьИД



Замена запросов SQL


Для замены запросов в журнале я использую следующий код:

//*******************************************
Процедура Выполнить()
    глКонтрагент=ВыбКонтрагент;
    глПользователь=ВыбПользователь;
    глТовар=ВыбТовар;
    глСкрыватьПомеченныеНаУдаление=ф_СкрыватьПомеченныеНаУдаление;
    
    
    стр="";
    глСтрокаОтбора="";
    Если ПустоеЗначение(ВыбКонтрагент)=0 Тогда         
        стр=стр+"SP47='"+ПолучитьИД(ВыбКонтрагент)+"' and ";
        глСтрокаОтбора=глСтрокаОтбора+"Контрагент: "+ВыбКонтрагент+";";
    КонецЕсли;
    Если ПустоеЗначение(ВыбПользователь)=0 Тогда
        стр=стр+"SP43='"+ПолучитьИД(ВыбПользователь)+"' and ";
        глСтрокаОтбора=глСтрокаОтбора+"  Пользователь: "+ВыбПользователь+";";
    КонецЕсли;
    Если ПустоеЗначение(ВыбТовар)=0 Тогда
        стр=стр+"SP46='"+ПолучитьИД(ВыбТовар)+"' and ";
        глСтрокаОтбора=глСтрокаОтбора+"  Товар: "+ВыбТовар+";";
    КонецЕсли;
    Если глСкрыватьПомеченныеНаУдаление=1 Тогда
        стр=стр+"ISMARK='0' and ";
        глСтрокаОтбора=глСтрокаОтбора+"  Не помеченные";
    КонецЕсли;    
    
    
    vk_hook.ТекстSQL="Select * from _1SJOURN(NOLOCK INDEX=JOURNAL) where IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC<=? order by IDJOURNAL, DATE_TIME_IDDOC";
    vk_hook.НовыйSQL="Select * from _1SJOURN(NOLOCK INDEX=JOURNAL) where "+стр+" IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC<=? order by IDJOURNAL, DATE_TIME_IDDOC";
    vk_hook.УстановитьЗаменуSQL();
    
    vk_hook.ТекстSQL="Select COUNT(*) from _1SJOURN(NOLOCK) where IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC<=? and DATE_TIME_IDDOC<=?";
    vk_hook.НовыйSQL="Select COUNT(*) from _1SJOURN(NOLOCK) where "+стр+" IDJOURNAL=? and DATE_TIME_IDDOC>=? and DATE_TIME_IDDOC<=? and DATE_TIME_IDDOC<=?";
    vk_hook.УстановитьЗаменуSQL();
    
    Форма.Закрыть();
КонецПроцедуры


Свойство vk_hook.ТекстSQL задает оригинальный текст SQL-запроса. Откуда его можно взять? Я беру его в буфер обмена (по нажатию Ctrl-C), выставив отображение SQL-запросов vk_hook.ПоказыватьSQL=1;

Свойство vk_hook.НовыйSQL задает измененный запрос SQL (в данном примере, я вставляю в него отбор по контрагенту, товару и пользователю.

Метод vk_hook.УстановитьЗаменуSQL(); выполняет собственно замену SQL-запроса. В системе можно установить несколько (до 200) таких замен.


Отбор в форме списка справочников


Часто удобно, когда отображается не весь справочник, а только его часть (например, по первым буквам наименования. Этот режим работы есть в 1С:Предприятие 8.0. Заменой запросов SQL это можно реализовать примерно так:

Процедура ПриОткрытии()
    стр="";
    ок=1;
    Если ВвестиСтроку(стр, "Введите первые буквы наименования товара", 100, 0, )<>1 Тогда
      ок=0;
    КонецЕсли;
    стр=СокрЛП(стр);
    Если стр="" Тогда
        ок=0;
    КонецЕсли;
    Если ок=1 Тогда    
        vk_hook.ТекстSQL="Select * from SC12(NOLOCK INDEX=DESCR) order by DESCR, ROW_ID";
        vk_hook.НовыйSQL="Select * from SC12(NOLOCK INDEX=DESCR) where DESCR LIKE '"+стр+"%' order by DESCR, ROW_ID";
        vk_hook.УстановитьЗаменуSQL();
        
    Иначе    
        vk_hook.ТекстSQL="Select * from SC12(NOLOCK INDEX=DESCR) order by DESCR, ROW_ID";
        vk_hook.УдалитьЗаменуSQL();
    КонецЕсли;    
КонецПроцедуры


Этот код расположен в форме списка справочника Товары. Перед открытием формы списка пользователь видит запрос на ввод первых букв наименования. Если он нажимает Enter, то справочник отображается "как обычно". Если же он вводит первые буквы, то добавляется отбор where DESCR LIKE '"+стр+"%'
Замечу, что можно написать "Кофе % мет", чтобы найти "Кофе черная метка" и т.п. (знак % - метасимвол).


Перехват SQLExecDirect


Дополнение от 24.09.2006 - добавлен перехват SQLExecDirect с той же функциональностью, что и в разработке Книга знаний: Исправление ошибки 1С:Предприятие 7.7/8.0 - 100% загрузка процессора при ожидании блокировки

Отличие - не требуется патч bkend.dll.

   vk_hook.ПерехватSQLExecDirect();
   vk_hook.МаксимальныйSleep=1024;
   vk_hook.СигнальныйФайл=КаталогИБ()+"romix.sig";

Через функцию SQLExecDirect тоже проходят SQL-запросы 1С (а именно те запросы, которые не требуют установки параметров). Их (теоретически) тоже можно изменять, однако, в данной версии компоненты это не реализовано.

Методы ПерехватSQLPrepare() и/или ПерехватSQLExecDirect() можно не вызывать, и тогда никакого воздействия на работу 1С они оказывать не будут (перехвата указанных системных вызовов не произойдет).




Предыдущая версия: http://x-romix.narod.ru/SqlLog.rar (137К)
(выполняет полный перехват всех функций подменой ODBC32.dll)

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2024 | Mista.ru

Яндекс.Метрика