При разработке отчетов в системе 1С:Предприятие 8.3 часто возникает задача подсчета статистики на основе данных табличных частей документов. Например, в приемной комиссии вуза необходимо посчитать, сколько абитуриентов предоставили оригиналы документов, а сколько — копии. На первый взгляд задача кажется простой, но новички часто сталкиваются с ситуацией, когда запрос выдает неверные цифры, хотя условия кажутся логически полными. Разберем по шагам, почему возникают такие ошибки и как написать оптимальный и корректный запрос.
Рассмотрим ситуацию: автор пытается посчитать количество копий и оригиналов прямо в списке выбора, обращаясь к табличной части через точку. В исходном коде использовалось следующее условие:
ВЫБОР
КОГДА АнкетаАбитуриента.ДокументыДляПоступления.ПредоставленаКопия = ИСТИНА
И АнкетаАбитуриента.ДокументыДляПоступления.НомерСтроки = 1
ИЛИ АнкетаАбитуриента.ДокументыДляПоступления.НомерСтроки > 1
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ
Проанализируем, почему это условие работает некорректно. Основная причина заключается в приоритете логических операций. В языке запросов 1С (как и в SQL) оператор И (AND) имеет более высокий приоритет, чем ИЛИ (OR). Это означает, что система интерпретирует выражение так:
ПредоставленаКопия = ИСТИНА И НомерСтроки = 1).НомерСтроки > 1).В итоге, любая строка документа, имеющая порядковый номер 2, 3 и далее, автоматически попадает под условие ИЛИ НомерСтроки > 1 и считается как «Копия», независимо от того, стоит ли там флаг ПредоставленаКопия. Именно поэтому в результате запроса все строки, кроме первой, ошибочно засчитывались как копии.
Для того чтобы условие работало верно, необходимо явно указать порядок выполнения операций с помощью скобок. Нам нужно, чтобы признак копии проверялся для каждой строки, независимо от её номера. Правильное условие в рамках конструкции ВЫБОР будет выглядеть так:
СУММА(ВЫБОР
КОГДА АнкетаАбитуриента.ДокументыДляПоступления.ПредоставленаКопия = ИСТИНА
И (АнкетаАбитуриента.ДокументыДляПоступления.НомерСтроки = 1
ИЛИ АнкетаАбитуриента.ДокументыДляПоступления.НомерСтроки > 1)
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК КоличествоКопий
Однако, обратите внимание: условие НомерСтроки = 1 ИЛИ НомерСтроки > 1 фактически охватывает все возможные строки документа. Если нам нужно просто посчитать количество строк, где установлен флаг, условие можно максимально упростить, убрав лишние проверки номеров строк:
СУММА(ВЫБОР
КОГДА АнкетаАбитуриента.ДокументыДляПоступления.ПредоставленаКопия
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК Копия,
СУММА(ВЫБОР
КОГДА НЕ АнкетаАбитуриента.ДокументыДляПоступления.ПредоставленаКопия
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК Оригинал
Важный совет: При работе с булевыми полями (ИСТИНА/ЛОЖЬ) в запросах 1С лучше опускать явное сравнение = ИСТИНА. Использование конструкции КОГДА ПолеБулево или КОГДА НЕ ПолеБулево делает код более читаемым и профессиональным.
Проанализируем структуру запроса автора. Обращение вида АнкетаАбитуриента.ДокументыДляПоступления.(...) создает так называемую вложенную таблицу. Хотя платформа 1С позволяет использовать такой синтаксис, это считается «плохим тоном» в разработке и часто ведет к трудноуловимым ошибкам и низкой производительности.
Основные недостатки вложенных таблиц:
Выясним, как сделать правильно. Вместо обращения к табличной части через точку от основного документа, следует использовать физическую таблицу табличной части и соединять её с «шапкой» документа.
Рассмотрим правильный архитектурный подход к решению этой задачи. Мы разделим запрос на получение данных из табличной части и их последующую группировку.
Документ.АнкетаАбитуриента.ДокументыДляПоступления.ЛЕВОЕ СОЕДИНЕНИЕ по полю Ссылка.СУММА к нашим условиям.Посмотрим на пример реализации такого запроса:
ВЫБРАТЬ
АнкетаТЧ.Ссылка.ФизЛицо КАК ФизЛицо,
АнкетаТЧ.Ссылка.Специальность КАК Специальность,
СУММА(ВЫБОР
КОГДА АнкетаТЧ.ПредоставленаКопия
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК КоличествоКопий,
СУММА(ВЫБОР
КОГДА НЕ АнкетаТЧ.ПредоставленаКопия
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК КоличествоОригиналов
ИЗ
Документ.АнкетаАбитуриента.ДокументыДляПоступления КАК АнкетаТЧ
ГРУППИРОВАТЬ ПО
АнкетаТЧ.Ссылка.ФизЛицо,
АнкетаТЧ.Ссылка.Специальность
В этом варианте мы получаем «плоскую» таблицу, которую легко выгрузить в ТЗ или использовать в качестве набора данных для СКД. Группировка гарантирует, что мы получим итоговые цифры по каждому человеку и специальности.
Если ваш отчет предполагает обработку большого объема данных (тысячи анкет), проанализируем возможность использования временных таблиц. Это позволит сначала отобрать нужные документы по фильтрам (например, по периоду или подразделению), а уже потом соединять их с табличными частями.
Пример использования временной таблицы:
// Помещаем отобранные анкеты во временную таблицу
ВЫБРАТЬ
Анкета.Ссылка КАК Ссылка,
Анкета.ФизЛицо КАК ФизЛицо,
Анкета.Специальность КАК Специальность
ПОМЕСТИТЬ ВТ_Анкеты
ИЗ
Документ.АнкетаАбитуриента КАК Анкета
ГДЕ
Анкета.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
;
// Соединяем временную таблицу с табличной частью для расчета итогов
ВЫБРАТЬ
ВТ.ФизЛицо,
ВТ.Специальность,
СУММА(ВЫБОР КОГДА ТЧ.ПредоставленаКопия ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) КАК Копии,
СУММА(ВЫБОР КОГДА НЕ ТЧ.ПредоставленаКопия ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) КАК Оригиналы
ИЗ
ВТ_Анкеты КАК ВТ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.АнкетаАбитуриента.ДокументыДляПоступления КАК ТЧ
ПО ВТ.Ссылка = ТЧ.Ссылка
ГРУППИРОВАТЬ ПО
ВТ.ФизЛицо,
ВТ.Специальность
Такой подход разделяет логику фильтрации документов и логику агрегации данных, что существенно упрощает отладку запроса. Кроме того, помните о нюансе с НомерСтроки: использование этого поля в бизнес-логике (как в исходном вопросе) крайне рискованно. Если пользователь переставит строки в документе местами, логика вашего отчета может нарушиться. Всегда старайтесь опираться на конкретные реквизиты (флаги, перечисления или ссылки), а не на порядковый номер в таблице.
Подводя итог, отметим, что для корректной работы запроса в 1С важно следить за приоритетом операторов, избегать вложенных выборок табличных частей и всегда использовать группировку при применении агрегатных функций. Эти простые правила помогут вам создавать надежные и быстрые отчеты.