При разработке отчетов в платформе 1С:Предприятие 7.7 нередко возникает классическая задача: получить список абсолютно всех позиций номенклатуры из справочника и сопоставить им текущие остатки из регистра. Если написать стандартный запрос к остаткам регистра, в результат попадут только те позиции, по которым на момент формирования отчета зафиксирован ненулевой остаток либо были движения за указанный период. Разберем подробнее, как средствами встроенного языка запросов 1С 7.7 реализовать аналог левого соединения (LEFT JOIN) справочника с регистром.
Проанализируем типовой исходный запрос, возвращающий только позиции с остатками:
//{{QUERY(Generate)
|Period from SelBegPeriod till SelEndPeriod;
|Sklad = Register.Tovar.Sklad;
|TOVAR = Register.Tovar.TOVAR;
|KOLICH = Register.Tovar.KOLICH;
|Stoim = Register.Tovar.Stoim;
|Function KolichEnd = EndRest(KOLICH);
|Function StoimEnd = EndRest(Stoim);
|Group Sklad;
|Group TOVAR;
|;
В языке запросов платформы 1С 7.7 для вывода всех элементов справочника (даже тех, по которым нет движений в регистре и остатки равны нулю) предназначен специальный модификатор Все (или All в англоязычном синтаксисе). Он указывается непосредственно в строке группировки по переменной справочника.
Разберем по шагам правильный синтаксис и порядок указания ключевых слов:
Без Групп (Without Groups) должен стоять перед модификатором Все (All).
Группировка Товар Без Групп Все;
// или с сохранением иерархии:
Группировка Товар Все;
Group TOVAR Without Groups All;
// или с сохранением иерархии:
Group TOVAR All;
Посмотрим на пример динамического формирования текста запроса с проверкой флага вывода иерархии:
ТекстЗапроса =
"//{{QUERY(Generate)
|Period from SelBegPeriod till SelEndPeriod;
|Sklad = Register.Tovar.Sklad;
|TOVAR = Register.Tovar.TOVAR;
|KOLICH = Register.Tovar.KOLICH;
|Stoim = Register.Tovar.Stoim;
|Function KolichEnd = EndRest(KOLICH);
|Function StoimEnd = EndRest(Stoim);
|Group Sklad;
|";
Если ФлагБезГрупп = 1 Тогда
ТекстЗапроса = ТекстЗапроса + "Group TOVAR Without Groups All;";
Иначе
ТекстЗапроса = ТекстЗапроса + "Group TOVAR All;";
КонецЕсли;
Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
// Обход результатов запроса
КонецЕсли;
Выясним причину разницы между модификаторами Все и Все ВошедшиеВЗапрос (IncludedInQuery):
EndRest) оказалось равным нулю.Рассмотрим подводные камни, с которыми можно столкнуться при использовании данного механизма:
Group Sklad;), то при добавлении Group TOVAR All; система выведет полный список товаров для каждого склада. Если у вас 10 складов и 10 000 товаров, выборка будет содержать 100 000 строк.Все последовательно сканирует всю таблицу справочника. На объемных информационных базах время выполнения запроса может существенно возрасти.Condition, строки с нулевыми остатками могут быть отсечены платформой до группировки.Если в базе данных содержится большой объем номенклатуры или использование модификатора Все приводит к зависанию отчета из-за декартова произведения складов и товаров, оптимально применить двухэтапную обработку данных:
Все (выбрать только реальные остатки) и выгрузить итоги в объект ТаблицаЗначений.ВыбратьЭлементы() и для каждого товара быстро получать остаток из таблицы через НайтиЗначение() или ПолучитьСтрокуПоНомеру().Посмотрим на пример реализации такого подхода в коде 1С 7.7:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{QUERY(Остатки)
|Период с ВыбНачПериода по ВыбКонПериода;
|Товар = Регистр.Товар.Товар;
|Колич = Регистр.Товар.Колич;
|Функция КонОст = КонОст(Колич);
|Группировка Товар Без Групп;
|";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
ТЗ = СоздатьОбъект("ТаблицаЗначений");
Запрос.Выгрузить(ТЗ, 0, 0);
Спр = СоздатьОбъект("Справочник.Номенклатура");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если Спр.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
ТекТовар = Спр.ТекущийЭлемент();
СтрокаТЗ = 0;
Если ТЗ.НайтиЗначение(ТекТовар, СтрокаТЗ, "Товар") = 1 Тогда
Остаток = ТЗ.ПолучитьЗначение(СтрокаТЗ, "КонОст");
Иначе
Остаток = 0;
КонецЕсли;
// Вывод строки отчета
КонецЦикла;
КонецЕсли;
Такой подход обеспечивает контролируемую скорость работы на любых объемах данных и гарантирует, что в итоговый отчет попадет вся номенклатура без избыточного дублирования строк.