Почему результаты запроса в СКД отличаются от консоли запросов и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1С:Розница Управленческий учет Торговля и дистрибуция
← На главную

Разберем классическую ситуацию, с которой сталкиваются многие разработчики 1С: один и тот же текст запроса выдает корректные цифры в консоли запросов (или обычной обработке), но показывает «астрономические» суммы при выполнении в отчете на базе Системы компоновки данных (СКД). Проанализируем, почему это происходит и как построить отчет правильно.

Выясним причину: декартово произведение при соединении табличных частей

Рассмотрим исходный запрос, который стал причиной проблемы. В нем выполняется ЛЕВОЕ СОЕДИНЕНИЕ двух табличных частей одного и того же документа ЧекККМ: Запасы и БезналичнаяОплата. Это критическая архитектурная ошибка в языке запросов 1С.

Когда мы соединяем две табличные части по полю Ссылка, СУБД сопоставляет каждую строку первой таблицы с каждой строкой второй таблицы в рамках одного документа. Проанализируем ситуацию на примере:

  1. В чеке 3 строки в таблице Запасы (три разных товара).
  2. Клиент оплатил чек двумя картами (2 строки в таблице БезналичнаяОплата).
  3. В результате соединения вместо 3 строк мы получим 3 * 2 = 6 строк.

В консоли запросов вы можете видеть «правильные» суммы в каждой отдельной строке, если не используете группировку. Однако, как только в дело вступает СКД или секция СГРУППИРОВАТЬ ПО, суммы этих 6 строк складываются, и результат завышается в несколько раз. Именно об этом предупреждают опытные разработчики: если в чеке больше одной строки оплаты или товара, данные «размножаются».

Почему СКД ведет себя иначе, чем консоль?

Выясним, почему же в обработке результаты кажутся «корректными», а в СКД — нет. Основная причина в том, что СКД — это не просто «исполнитель запроса», а генератор. Перед отправкой запроса в СУБД компоновщик трансформирует его исходя из настроек отчета.

Рассмотрим ключевые механизмы трансформации:

  1. Удаление полей: Если вы не выбрали поле в «Выбранных полях» настроек СКД, компоновщик может исключить его из секции ВЫБРАТЬ и, что более важно, из секции СГРУППИРОВАТЬ ПО. Это мгновенно меняет агрегацию данных.
  2. Работа с ресурсами: В СКД агрегатные функции (СУММА, МАКСИМУМ) в самом тексте запроса часто работают не так, как ожидается. СКД рассчитывает итоги на основе вкладки «Ресурсы». Если поле не добавлено в ресурсы, расчет по группировкам будет некорректным.
  3. Роли полей: СКД использует роли (например, «Без дублей»), чтобы понимать, как объединять записи. Если роли настроены неверно, компоновщик может неправильно интерпретировать границы записей при соединении ТЧ.

Решение проблемы через временные таблицы

Чтобы гарантированно избежать дублирования сумм и расхождений в результатах, необходимо отказаться от прямого соединения табличных частей. Разберем по шагам правильный алгоритм построения запроса.

Шаг 1. Подготовка данных по запасам. Сначала выберем данные из товаров, сгруппируем их по документам и поместим во временную таблицу.


ВЫБРАТЬ
    ЧекЗапасы.Ссылка КАК Ссылка,
    ЧекЗапасы.Партия.Наименование КАК ПартияНаименование,
    СУММА(ЧекЗапасы.Сумма) КАК СуммаТоваров
ПОМЕСТИТЬ ВТ_Запасы
ИЗ
    Документ.ЧекККМ.Запасы КАК ЧекЗапасы
ГДЕ
    ЧекЗапасы.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО
    ЧекЗапасы.Ссылка,
    ЧекЗапасы.Партия.Наименование
;

Шаг 2. Подготовка данных по оплатам. Аналогично соберем суммы безналичных оплат в отдельную временную таблицу, сгруппировав их по ссылке на документ.


ВЫБРАТЬ
    ЧекОплата.Ссылка КАК Ссылка,
    СУММА(ЧекОплата.Сумма) КАК СуммаБезнал
ПОМЕСТИТЬ ВТ_Оплаты
ИЗ
    Документ.ЧекККМ.БезналичнаяОплата КАК ЧекОплата
ГДЕ
    ЧекОплата.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО
    ЧекОплата.Ссылка
;

Шаг 3. Финальное соединение. Теперь соединим подготовленные данные. Поскольку в каждой временной таблице на один документ (или на одну партию внутри документа) приходится строго одна строка, «размножения» данных не произойдет.


ВЫБРАТЬ
    ВТ_Запасы.ПартияНаименование,
    ВТ_Запасы.СуммаТоваров КАК Наличные, // Здесь логика разделения оплаты
    ВТ_Оплаты.СуммаБезнал КАК Безнал,
    ВТ_Запасы.Ссылка.Номер КАК Номер
ИЗ
    ВТ_Запасы КАК ВТ_Запасы
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Оплаты КАК ВТ_Оплаты
ПО ВТ_Запасы.Ссылка = ВТ_Оплаты.Ссылка

Как проверить итоговый запрос в СКД

Проанализируем ситуацию: если вы все еще видите расхождения, нужно посмотреть на «реальный» запрос, который СКД отправляет в базу. Сделать это можно следующими способами:

Настройка ресурсов в СКД

Помните, что для корректной работы отчета в СКД крайне желательно выносить агрегацию на вкладку «Ресурсы». Рассмотрим, как это сделать правильно:

  1. В самом тексте запроса выбирайте детальные данные (без СУММА и СГРУППИРОВАТЬ).
  2. На вкладке «Ресурсы» добавьте поля Сумма, Безнал и т.д.
  3. В колонке «Рассчитывать по...» укажите уровни группировок, если логика расчета суммы отличается для документа и для партии.

Важный момент: если вы используете поле ЧекККМ.ПолученоНаличными, помните, что это реквизит шапки. Если в чеке 10 строк товаров, и вы выводите этот реквизит в детальных записях без ресурсов, СКД может просуммировать его 10 раз. Чтобы этого не случилось, в ресурсах для таких полей используйте выражение МАКСИМУМ(ПолученоНаличными) или СРЕДНЕЕ(ПолученоНаличными) в разрезе документа.

Таким образом, использование временных таблиц для разделения данных из разных табличных частей и правильная настройка ресурсов — это единственный надежный способ получить идентичные и правильные результаты как в консоли, так и в сложном отчете СКД.

← На главную