При работе с Динамическими списками в 1С часто возникает задача отображения агрегированных данных, например, общей суммы по строкам табличной части каждого документа. Стандартный подход к формированию запросов для Динамического списка предполагает, что каждая строка списка соответствует одной записи из базы данных. Если мы хотим показать сумму по табличной части документа, которая содержит много строк, нам нужно специальным образом подготовить эти данные. Рассмотрим, как мы можем решить эту проблему, используя возможности языка запросов 1С.
Выясним причину, по которой прямое суммирование всей табличной части для каждой строки документа в Динамическом списке вызывает сложности. Динамический список по своей сути является "плоским" представлением данных: одна строка списка соответствует одной записи в источнике данных. Если мы попытаемся просто присоединить табличную часть и суммировать ее напрямую, без должной группировки, Динамический список не сможет корректно отобразить агрегированные данные, поскольку он ожидает увидеть уникальный "главный" элемент для каждой строки. Нам необходимо, чтобы наш запрос возвращал одну строку для каждого документа, содержащую уже вычисленную сумму по его табличной части.
Для решения поставленной задачи мы будем использовать комбинацию ЛЕВОГО СОЕДИНЕНИЯ и ГРУППИРОВКИ (СГРУППИРОВАТЬ ПО) в запросе к данным. Это позволит нам получить одну строку для каждого документа, в которой будет рассчитана необходимая сумма по его табличной части. Давайте разберем этот подход по шагам.
Динамическом списке, например, Ссылка, Номер, Дата.
ВЫБРАТЬ
Списание.Ссылка,
Списание.Номер,
Списание.Дата
ИЗ
Документ.Списание КАК Списание
ЛЕВОЕ СОЕДИНЕНИЕ для связи документа с его табличной частью. Это важно, чтобы в список попадали документы, даже если их табличная часть пуста (в таком случае сумма будет равна NULL или 0). В нашем примере, допустим, это табличная часть Товары документа Списание и нам нужно получить сумму по полю Количество.
ВЫБРАТЬ
Списание.Ссылка,
Списание.Номер,
Списание.Дата
ИЗ
Документ.Списание КАК Списание
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Списание.Товары КАК Товары
ПО Списание.Ссылка = Товары.Ссылка
СУММА() для получения необходимого итога по полю Количество.
ВЫБРАТЬ
Списание.Ссылка,
Списание.Номер,
Списание.Дата,
СУММА(Товары.Количество) КАК СуммаКоличества
ИЗ
Документ.Списание КАК Списание
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Списание.Товары КАК Товары
ПО Списание.Ссылка = Товары.Ссылка
Списание.Ссылка, Списание.Номер и Списание.Дата.
ВЫБРАТЬ
Списание.Ссылка,
Списание.Номер,
Списание.Дата,
СУММА(Товары.Количество) КАК СуммаКоличества
ИЗ
Документ.Списание КАК Списание
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Списание.Товары КАК Товары
ПО Списание.Ссылка = Товары.Ссылка
СГРУППИРОВАТЬ ПО
Списание.Ссылка,
Списание.Номер,
Списание.Дата
Обратите внимание, что мы включили Списание.Ссылка в СГРУППИРОВАТЬ ПО, так как это поле является уникальным идентификатором документа и гарантирует, что каждая строка в итоговом результате будет соответствовать одному документу.
Полученный запрос следует использовать в качестве основного запроса для вашего Динамического списка. Для этого:
Динамический список.Динамического списка.Основная таблица (или Запрос, в зависимости от версии платформы и способа настройки) установите тип источника данных Произвольный запрос.После этого Динамический список будет отображать для каждой строки (каждого документа Списание) его Номер, Дату и рассчитанную СуммуКоличества из табличной части Товары. Вы сможете добавить это новое поле СуммаКоличества в список отображаемых колонок Динамического списка через настройки формы. При необходимости программно управлять расположением добавленных элементов подойдёт решение для программного перемещения колонок динамического списка.
Рассмотрим подробнее некоторые нюансы и другие подходы к решению подобной задачи:
Использование ЛЕВОГО СОЕДИНЕНИЯ является ключевым для корректной работы. Если бы мы использовали ВНУТРЕННЕЕ СОЕДИНЕНИЕ, в наш список попали бы только те документы, у которых есть хотя бы одна строка в табличной части Товары. Документы с пустой табличной частью были бы проигнорированы. ЛЕВОЕ СОЕДИНЕНИЕ гарантирует, что все документы будут представлены в списке, а для тех, у кого нет строк в табличной части Товары, поле СуммаКоличества будет равно NULL. Вы можете использовать функцию ЕСТЬNULL() или ВЫБОР КОГДА в запросе, чтобы преобразовать NULL в 0, если это необходимо для отображения.
ВЫБРАТЬ
Списание.Ссылка,
Списание.Номер,
Списание.Дата,
ЕСТЬNULL(СУММА(Товары.Количество), 0) КАК СуммаКоличества
ИЗ
Документ.Списание КАК Списание
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Списание.Товары КАК Товары
ПО Списание.Ссылка = Товары.Ссылка
СГРУППИРОВАТЬ ПО
Списание.Ссылка,
Списание.Номер,
Списание.Дата
Для очень больших объемов данных (десятки и сотни тысяч документов с объемными табличными частями) запросы с агрегатными функциями могут работать медленнее. В таких случаях мы можем рассмотреть следующие подходы:
СуммаВсехТоваров. При записи документа (в обработчике ПриЗаписи()) рассчитывать эту сумму и записывать ее в данный реквизит. Тогда в Динамическом списке мы просто будем обращаться к этому полю напрямую, что существенно ускорит отображение, так как не потребуется выполнять ресурсоемкий запрос с агрегацией каждый раз. Это может быть оптимальным решением для документов, где сумма редко меняется или не требует мгновенного пересчета при каждом открытии списка.
Пример кода в модуле объекта документа Списание:
Процедура ПриЗаписи(Отказ)
СуммаВсехТоваров = 0;
Для Каждого СтрокаТЧ Из Товары Цикл
СуммаВсехТоваров = СуммаВсехТоваров + СтрокаТЧ.Количество;
КонецЦикла;
КонецПроцедуры
Затем в запросе Динамического списка вы просто выбираете Списание.СуммаВсехТоваров.
Мы видим, что наиболее эффективным и прямым способом отображения агрегированных данных из табличной части документов в Динамическом списке является использование запроса с ЛЕВЫМ СОЕДИНЕНИЕМ и ГРУППИРОВКОЙ. Этот подход позволяет нам подготовить данные таким образом, чтобы каждая строка в Динамическом списке соответствовала одному документу с уже вычисленной итоговой суммой. Всегда анализируйте объем данных и требования к производительности, чтобы выбрать наиболее подходящий метод реализации. Для ознакомления с другими практическими вариантами добавления полей в форму можно изучить руководство по методам доработки динамических списков.