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