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