При разработке отчетов и обработок в 1С часто возникает задача: выбрать строки табличных частей сразу из нескольких разных документов за определенный период и вывести результат в виде иерархической структуры: Дата поступления → Вид документа → Документ → Строки табличной части. Разберем типичные ошибки при реализации такого запроса и рассмотрим правильную архитектуру решения с использованием ПостроительОтчета.
Посмотрим на распространенную ошибку: попытка соединить регистр накопления или шапку документа с вложенными подзапросами, где снова дублируются те же самые таблицы. В исходном запросе автора выполнялось многократное левое соединение регистра остатков с самим собой и подзапросом, что приводило к:
СГРУППИРОВАТЬ ПО вместо ИТОГИ ПО: секция СГРУППИРОВАТЬ ПО сворачивает детальные строки и не строит иерархическое дерево данных. Для построения многоуровневой структуры требуется секция ИТОГИ.Разберем по шагам, как правильно составить единый запрос:
Документ.ИмяДокумента.Товары каждого нужного вида документа.ГДЕ ТабЧасть.Ссылка.ДатаПоступления МЕЖДУ &ДатаНач И &ДатаКон."Заявка на перемещение" КАК ВидДокумента), чтобы на уровне группировок различать типы документов.ОБЪЕДИНИТЬ ВСЕ (оператор ОБЪЕДИНИТЬ без ВСЕ выполнять не рекомендуется, так как он делает неявный DISTINCT, замедляя выполнение).ИТОГИ ... ПО.Посмотрим на пример правильного текста запроса:
ВЫБРАТЬ
"Заявка на перемещение" КАК ВидДокумента,
ЗаявкаТовары.Ссылка.рар_ДатаПоступления КАК ДатаПоступления,
ЗаявкаТовары.Ссылка КАК Документ,
ЗаявкаТовары.Номенклатура КАК Номенклатура,
ЗаявкаТовары.СерияНоменклатуры КАК СерияНоменклатуры,
ЗаявкаТовары.Количество КАК Количество,
ЗаявкаТовары.ДокументРезерва КАК ДокументРезерва
ИЗ
Документ.рар_ЗаявкаНаВнутреннееПеремещениеТоваров.Товары КАК ЗаявкаТовары
ГДЕ
ЗаявкаТовары.Ссылка.рар_ДатаПоступления МЕЖДУ &ДатаНач И &ДатаКон
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Поступление товаров" КАК ВидДокумента,
ПоступлениеТовары.Ссылка.рар_ДатаПоступления КАК ДатаПоступления,
ПоступлениеТовары.Ссылка КАК Документ,
ПоступлениеТовары.Номенклатура КАК Номенклатура,
ПоступлениеТовары.СерияНоменклатуры КАК СерияНоменклатуры,
ПоступлениеТовары.Количество КАК Количество,
ПоступлениеТовары.ДокументРезерва КАК ДокументРезерва
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТовары
ГДЕ
ПоступлениеТовары.Ссылка.рар_ДатаПоступления МЕЖДУ &ДатаНач И &ДатаКон
ИТОГИ
СУММА(Количество)
ПО
ДатаПоступления,
ВидДокумента,
Документ
Если результат запроса обрабатывается вручную в коде, обход дерева итогов выполняется последовательно через вызовы метода Выбрать() с нужными типами обхода:
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("ДатаНач", ДатаНач);
Запрос.УстановитьПараметр("ДатаКон", ДатаКон);
РезультатЗапроса = Запрос.Выполнить();
// 1 уровень - Дата поступления
ВыборкаДата = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаДата.Следующий() Цикл
// 2 уровень - Вид документа
ВыборкаВид = ВыборкаДата.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаВид.Следующий() Цикл
// 3 уровень - Ссылка на документ
ВыборкаДокумент = ВыборкаВид.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаДокумент.Следующий() Цикл
// 4 уровень - Детальные записи (строки табличной части)
ВыборкаСтроки = ВыборкаДокумент.Выбрать(ОбходРезультатаЗапроса.Прямой);
Пока ВыборкаСтроки.Следующий() Цикл
// Обработка полей детальной строки
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
При передаче запроса в ПостроительОтчета можно использовать расширения языка запросов (конструкции в фигурных скобках {}). Построитель отчета способен самостоятельно управлять итогами на основании измерений строк.
Рассмотрим, как инициализировать построитель отчета и передать параметры:
Построитель = Новый ПостроительОтчета;
Построитель.Текст =
"ВЫБРАТЬ
| ""Заявка на перемещение"" КАК ВидДокумента,
| ЗаявкаТовары.Ссылка.рар_ДатаПоступления КАК ДатаПоступления,
| ЗаявкаТовары.Ссылка КАК Документ,
| ЗаявкаТовары.Номенклатура КАК Номенклатура,
| ЗаявкаТовары.Количество КАК Количество
|{ВЫБРАТЬ
| ВидДокумента,
| ДатаПоступления,
| Документ.*,
| Номенклатура.*,
| Количество}
|ИЗ
| Документ.рар_ЗаявкаНаВнутреннееПеремещениеТоваров.Товары КАК ЗаявкаТовары
|{ГДЕ
| ЗаявкаТовары.Ссылка.рар_ДатаПоступления МЕЖДУ &ДатаНач И &ДатаКон}
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ""Поступление товаров"",
| ПоступлениеТовары.Ссылка.рар_ДатаПоступления,
| ПоступлениеТовары.Ссылка,
| ПоступлениеТовары.Номенклатура,
| ПоступлениеТовары.Количество
|{ВЫБРАТЬ
| ВидДокумента,
| ДатаПоступления,
| Документ.*,
| Номенклатура.*,
| Количество}
|ИЗ
| Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТовары
|{ГДЕ
| ПоступлениеТовары.Ссылка.рар_ДатаПоступления МЕЖДУ &ДатаНач И &ДатаКон}";
Построитель.Параметры.Вставить("ДатаНач", НачалоДня(ДатаНач));
Построитель.Параметры.Вставить("ДатаКон", КонецДня(ДатаКон));
// Настройка группировок строк построителя
Построитель.ИзмеренияСтроки.Очистить();
Построитель.ИзмеренияСтроки.Добавить("ДатаПоступления");
Построитель.ИзмеренияСтроки.Добавить("ВидДокумента");
Построитель.ИзмеренияСтроки.Добавить("Документ");
// Формирование вывода
Построитель.Выполнить();
Построитель.Вывести(ЭлементыФормы.ПолеТабличногоДокумента);
Важные правила при работе с Построителем отчета и ОБЪЕДИНИТЬ ВСЕ:
ОБЪЕДИНИТЬ ВСЕ, должны строго совпадать.{ГДЕ} и {ВЫБРАТЬ} должны корректно дублироваться во всех ветках объединения, чтобы пользовательские отборы применялись ко всем типам документов одинаково.