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