Начало...
Вначале допишем в глобальном модуле базы OLE немного строк, которые нам помогут в работе:
//************************************************************** Перем СписокЗначенийЗапроса[10] Экспорт; // Мы в них "запихнем" значения для запроса //************************************************************** Функция СкорректироватьСписок(ИндексМассива, Действие, ТипОбъекта = "", ВидОбъекта = "", Параметр1 = "", Параметр2 = "", Параметр3 = "", // Ну и далее по параметрам, сколько надо // ………………… Параметр99 = "") Экспорт
ИндексМассива=Число(ИндексМассива); Если ИндексМассива = 0 Тогда Возврат -99; // Ошибка: Не указали индекс массива ? КонецЕсли; Если Действие = 1 Тогда // Очистить список значений СписокЗначенийЗапроса[ИндексМассива].УдалитьВсе(); Возврат 1; ИначеЕсли Действие = 2 Тогда // Добавить объект в список Если ТипОбъекта = "Документ" Тогда Если ВидОбъекта = "" Тогда Возврат -99; // Ошибка: Передавайте нормальный вид объекта! КонецЕсли; Попытка Док = СоздатьОбъект("Документ."+ВидОбъекта); Исключение Возврат -99; // Ошибка: Попытка обращения к неверному объекту КонецПопытки; Если Док.НайтиПоНомеру(Параметр1,Параметр2)=1 Тогда СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(Док.ТекущийДокумент()); Возврат 1; // Нашли документ Иначе Возврат 0; // Не нашли документ :( КонецЕсли; ИначеЕсли ТипОбъекта = "Справочник" Тогда Если ВидОбъекта = "" Тогда Возврат -99; // Ошибка: Передавайте нормальный вид объекта! КонецЕсли; Попытка Спр = СоздатьОбъект("Справочник."+ВидОбъекта); Исключение Возврат -99; // Ошибка: Попытка обращения к неверному объекту КонецПопытки; // Параметр1 - Код // Параметр2 - наименование // Параметр3 - флаг глобального поиска Если Спр.НайтиПоКоду(Параметр1,Число(Параметр3))=1 Тогда СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(Спр.ТекущийЭлемент()); Возврат 1; // Нашли элемент ИначеЕсли Спр.НайтиПоНаименованию(Параметр2,Число(Параметр3))=1 Тогда СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(Спр.ТекущийЭлемент()); Возврат 1; // Нашли элемент Иначе Возврат 0; // Не нашли элемент :( КонецЕсли; ИначеЕсли ТипОбъекта = "Счет" Тогда // Вид объекта - Идентификатор плана счетов // Параметр1 - Код счета Попытка Если ВидОбъекта<>"" Тогда ИскомыйСчет = СчетПоКоду(Параметр1, ПланСчетов.ЗначениеПоИдентификатору(ВидОбъекта)); Иначе ИскомыйСчет = СчетПоКоду(Параметр1); КонецЕсли; Если ПустоеЗначение(ИскомыйСчет) = 1 Тогда Возврат 0; // не нашли счет :( Иначе СписокЗначенийЗапроса[ИндексМассива].ДобавитьЗначение(ИскомыйСчет); Возврат 1; // нашли счет КонецЕсли; Исключение Возврат -99; // Ошибка: Неверный тип объекта КонецПопытки; ИначеЕсли Действие = 3 Тогда // Вернуть размер списка Возврат СписокЗначенийЗапроса[ИндексМассива].РазмерСписка(); Иначе Возврат -99; // Ошибка: Неверное действие КонецЕсли; Возврат -999; // ??? КонецЕсли; КонецФункции
//************************************************************** Процедура ПриНачалеРаботыСистемы() // Данная процедура уже есть в глобальном модуле, просто надо // дописать в ней несколько строк: Для Сч=1 По 10 Цикл СписокЗначенийЗапроса[Сч]=СоздатьОбъект("СписокЗначений"); КонецЦикла; КонецПроцедуры //**************************************************************
Теперь начинаем потихоньку писать сам запрос. Что мы имеем: В форме диалога местной базы несколько реквизитов диалога (либо местные переменные):
-
Даты периода (НачДата и КонДата)
-
Элементы справочников для фильтрации (ВыбТовар, ВыбФирма, ВыбКлиент, и т.д.)
-
Какие-либо флажки (ТолькоЗамерзающийЗимойТовар , ..)
Мы начинаем писать запрос и сразу попадаем в такую ловушку:
ТекстЗапроса = " Период с НачДата по КонДата; ";
Вроде все в порядке, но такой запрос не выполнится в базе OLE, так как там понятия не имеют, что такое НачДата и КонДата :)) Ведь эти переменные действительны только для местной базы! Переписываем запрос заново:
ТекстЗапроса = " Период с '" + НачДата + "' по '" + КонДата + "'; // Будет типа '01.01.02' // т.е. прямое представление даты, которое всегда поймет любой запрос | Товар = Регистр.ОстаткиТоваров.Товар; | Фирма = Регистр.ОстаткиТоваров.Фирма; | Склад = Регистр.ОстаткиТоваров.Склад; | Остаток = Регистр.ОстаткиТоваров.Остаток; | Группировка Товар без групп; | Группировка Документ; | Функция НачОст = НачОст(Остаток); | Функция КонОст = КонОст(Остаток); | Функция ПрихОст = Приход(Остаток); | Функция РасхОст = Расход(Остаток);";
Так... Дошли до условий отбора в запросе. Рассмотрим два варианта, когда выбран ВыбТовар:
// 1-й вариант - когда выбран элемент справочника (не группа). // Самый простой случай - коды товаров совпадают абсолютно // Вариант 1а. Если ВыбТовар.Выбран()=1 Тогда ТекстЗапроса = ТекстЗапроса + " | Условие (Товар.Код = " +ВыбТовар.Код+");"; КонецЕсли; // Вариант 1б. Чтоб запрос быстрее был: // Вначале добавим к запросу переменную в общем списке: | КодТовара = Регистр.ОстаткиТоваров.Товар.Код; // А уж потом добавим к запросу условие (такое условие будет выполнятся проще, так как // запрос при формировании таблицы запроса сразу сформирует отдельную колонку кодов и по // ней уже будет отбирать, а не будет каждый раз при обработке товаров извлекать из них // код): Если ВыбТовар.Выбран()=1 Тогда ТекстЗапроса = ТекстЗапроса + " | Условие (КодТовара = " +ВыбТовар.Код+");"; КонецЕсли;
Казалось бы все очень просто. По аналогии - если уникальность для товаров ведется по наименованию, то простой заменой слова "код" на "наименование" мы решаем вопрос и здесь. Теперь рассмотрим, когда мы выбрали группу, т.е. текст условия должен будет выглядеть так:
| Условие (Товар.ПринадлежитГруппе(КакаяТоГруппа)=1);
И здесь, правда можно проблему решить "двумями путями" :)) Первый пусть - когда мы имеем дело с двухуровне вымсправочником. Тогда проблема группы решается также просто, как и в 1-м варианте:
// Добавляем в списке переменных строку: | КодРодителя = Регистр.ОстаткиТоваров.Товар.Родитель.Код; // Далее пишем условие: Если ВыбТовар.Выбран()=1 Тогда ТекстЗапроса = ТекстЗапроса + " | Условие (КодРодителя = " +ВыбТовар.Код+");"; КонецЕсли; // В качестве домашнего задания - переписать условие по наименоваиню :)))
А если справочник очень даже многоуровневый? Вот для этого мы и используем написанную ранее функцию. Предположим, что список значений запроса с индексом массива " 1 " мы будем использовать для хранения подобных значений (например, хранить в нем группы товаров, клиентов) для хитрых условий. Итак, например, в ВыбТовар у нас указана группа товаров, а в ВыбКлиент - группа клиентов, которым мы товары группы ВыбТовар продавали. Кроме того, мы должны пропустить накладные возвратов поставщикам, и не забыть, что товары надо еще отбирать по флажку ТолькоЗамерзающийЗимойТовар:
// Очистим список значений запроса Результат = БазаОле.EvalExpr("СкорректироватьСписок(1,1)"); // Закинем в список значений запроса группу товаров (он сам найдет ее в базе OLE) // И запоминаем (в уме), что этой группе соответствует 1-е значение списка Результат = БазаОле.EvalExpr("СкорректироватьСписок(1, 2 , ""Справочник"", """ +
ВыбТовар.Вид())+ """," + ВыбТовар.Код + ", """ + ВыбТовар.Наименование + """)"); // Теперь закинем в список значений запроса группу клиентов // И запоминаем, что этой группе соответствует 2-е значение списка Результат = БазаОле.EvalExpr("СкорректироватьСписок(1, 2 , ""Справочник"", """ +
ВыбКлиент.Вид())+ """," + ВыбКлиент.Код + ", """ + ВыбКлиент.Наименование + """)"); // А еще до кучи и фирму из ВыбФирма // И запоминаем, что этой фирме соответствует 3-е значение списка Результат = БазаОле.EvalExpr("СкорректироватьСписок(1, 2 , ""Справочник"", """ +
ВыбФирма.Вид())+ """," + ВыбФирма.Код + ", """ + ВыбФирма.Наименование + """)"); // Теперь формируем текст запроса ТекстЗапроса = " Период с '"+НачДата+ "' по '"+КонДата+"'; | Товар = Документ.РасходнаяНакладная.Товар; | Замерзает = Документ.РасходнаяНакладная.Товар.ЗамерзаетЗимой; | Признак = Документ.РасходнаяНакладная.ПризнакНакладной; | Фирма = Документ.РасходнаяНакладная.Фирма; | Клиент = Документ.РасходнаяНакладная.Клиент; | Количество = Документ.РасходнаяНакладная.Количество; | СуммаДок = Документ.РасходнаяНакладная.Сумма; | Группировка Товар без групп; | Группировка Документ; | Функция СуммаОтгрузки=Сумма(СуммаДок); | Условие (Признак<>Перечисление.ПризнРасхНакл.ВозвратПоставщику); | Условие (Замерзает = " + ТолькоЗамерзающийЗимойТовар + "); // Внимание! Начинается: | Условие (Товар.ПринадлежитГруппе(СписокЗначенийЗапроса[1].ПолучитьЗначение(1))=1); | Условие (Клиент.ПринадлежитГруппе(СписокЗначенийЗапроса[1].ПолучитьЗначение(2))=1); | Условие (Фирма= СписокЗначенийЗапроса[1].ПолучитьЗначение(3));";
Уфф. Вроде все… Остается только запустить запрос:
Запрос = БазаОле.CreateObject("Запрос"); Если Запрос.Выполнить(ТекстЗапроса)=0 Тогда Предупреждение("Запрос безутешен!"); Возврат; КонецЕсли;
Ну, а с реквизитами запроса разбираемся так же, как указано было выше в предыдущих разделах… И не забываем, что кроме хранения конкретных значений, можно использовать другие списки значений запроса. Например, можно заполнить какой-либо список значений запроса списком клиентов и использовать его в запросе:
// Всякими правдами/неправдами заполнили список значений (хотя бы через другой запрос :)) // конкретными клиентами… // Предположим, индекс массива равен "2". Тогда в тексте запроса появится следующее: | Условие (Клиенты в СписокЗначенийЗапроса[2]);
P.S. Чего еще
нет: перенос реквизитов неограниченной длины, более подробно остановиться
на "периодических реквихитах"…
ГРОМАДНЕЙШИЕ
ИЗВИНЕНИЯ ЗА ВОЗМОЖНЫЕ СИНТАКСИЧЕСКИЕ И ОРФОГРАФИЧЕСКИЕ ОШИБКИ В
ДОКУМЕНТЕ - ПИСАЛ БЕЗ ПРОВЕРКИ В 1С, БОЛЬШУЮ ЧАСТЬ - ПО ПАМЯТИ.
ЕСЛИ ОБНАРУЖИТЕ ОШИБКИ, ДА И ВООБЩЕ, ЕСЛИ ЕСТЬ ВОПРОСЫ ПО OLE -
ПИШИТЕ. ЕСЛИ ВЫКРОЮ ВРЕМЯ, ТО ПОИЩУ РЕШЕНИЕ…
С наилучшими пожеланиями, Руководитель информационно-технического отдела ООО МФФ "Аконит" Егоров Андрей Викторович
|