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