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