Почему не схлопываются строки в группировке запроса 1С и как это исправить

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

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

Разбор базовой механики группировки

Для начала проанализируем ситуацию: у нас есть набор данных, где информация распределена по периодам (например, 12 колонок для месяцев). Мы хотим видеть одну строку по контрагенту, где в каждой колонке будет стоять соответствующее значение. Если строки «не схлопываются», это означает только одно: в полях, указанных в блоке группировки, есть различия. Для СУБД значения "Иванов" и "Иванов " (с пробелом) или две даты, различающиеся на одну секунду, — это абсолютно разные записи.

Рассмотрим правильную структуру запроса, к которой необходимо прийти для агрегации данных:


|ВЫБРАТЬ
|    ВТ_Пол.Контрагент КАК Контрагент,
|    ВТ_Пол.Номенклатура КАК Номенклатура,
|    СУММА(ВТ_Пол.Количество1) КАК Количество1,
|    СУММА(ВТ_Пол.Сумма1) КАК Сумма1,
|    СУММА(ВТ_Пол.Количество2) КАК Количество2,
|    СУММА(ВТ_Пол.Сумма2) КАК Сумма2
|ИЗ
|    ВТ_Данные КАК ВТ_Пол
|СГРУППИРОВАТЬ ПО
|    ВТ_Пол.Контрагент,
|    ВТ_Пол.Номенклатура

В этом примере поля Контрагент и Номенклатура являются измерениями, а суммы и количества — ресурсами. Все, что не обернуто в агрегатную функцию (СУММА, МАКСИМУМ, МИНИМУМ), обязано присутствовать в блоке СГРУППИРОВАТЬ ПО.

Проблема 1: Скрытое время в датах (Поле Период)

Выясним самую распространенную причину неудачных группировок. Если в блоке СГРУППИРОВАТЬ ПО указано поле Период, и данные в таблицу попали из документов или разных регистров, время в этих датах может отличаться. Визуально в отчете вы можете видеть 01.01.2023, но внутри системы одна запись может иметь время 10:00:00, а другая — 12:00:00.

Рассмотрим, как правильно нормализовать период, чтобы строки объединились в рамках месяца:


|ВЫБРАТЬ
|    НАЧАЛОПЕРИОДА(ВТ_Пол.Период, МЕСЯЦ) КАК ПериодМесяц,
|    ВТ_Пол.Контрагент КАК Контрагент,
|    СУММА(ВТ_Пол.Сумма1) КАК Сумма1
|ИЗ
|    ВТ_Пол КАК ВТ_Пол
|СГРУППИРОВАТЬ ПО
|    НАЧАЛОПЕРИОДА(ВТ_Пол.Период, МЕСЯЦ),
|    ВТ_Пол.Контрагент

Функция НАЧАЛОПЕРИОДА отсекает «лишнюю» точность времени и приводит все даты к единому стандарту (например, к 00:00:00 первого числа месяца). Если же период в итоговой таблице вообще не важен для вывода, его следует просто исключить из списка полей ВЫБРАТЬ и из блока СГРУППИРОВАТЬ ПО.

Проблема 2: Обработка NULL при соединениях

Проанализируем ситуацию, когда данные собираются из нескольких таблиц через ЛЕВОЕ СОЕДИНЕНИЕ. Если для какого-то контрагента во второй таблице нет данных, система вернет значение NULL. Группировка по полю, содержащему NULL, и полю со значением (даже если это пустая строка или ноль) создаст две разные строки.

Для ресурсов (числовых показателей) использование функции ЕСТЬNULL критически важно для корректного суммирования:


|ВЫБРАТЬ
|    ВТ_Пол.Контрагент КАК Контрагент,
|    СУММА(ЕСТЬNULL(ВТ_Пол.Количество1, 0)) КАК Количество1,
|    СУММА(ЕСТЬNULL(ВТ_Пол.Сумма1, 0)) КАК Сумма1
|ИЗ
|    ВТ_Пол КАК ВТ_Пол
|СГРУППИРОВАТЬ ПО
|    ВТ_Пол.Контрагент

Применение ЕСТЬNULL(..., 0) гарантирует, что пустые значения будут интерпретированы как математические нули и корректно сложатся с другими числами в рамках группировки.

Проблема 3: Различия в точности чисел (Поле Доля)

Посмотрим на пример, где в группировке участвует поле с типом «Число», например, Доля. Если это поле является результатом вычисления (деления), значения могут отличаться в 10-м знаке после запятой (например, 0.3333333333 и 0.3333333334). В этом случае строки никогда не схлопнутся.

Разберем, как принудительно ограничить точность группировочного поля:


|ВЫБРАТЬ
|    ВЫРАЗИТЬ(ВТ_Пол.Доля КАК ЧИСЛО(15, 2)) КАК Доля,
|    ВТ_Пол.Контрагент КАК Контрагент,
|    СУММА(ВТ_Пол.Сумма1) КАК Сумма1
|ИЗ
|    ВТ_Пол КАК ВТ_Пол
|СГРУППИРОВАТЬ ПО
|    ВЫРАЗИТЬ(ВТ_Пол.Доля КАК ЧИСЛО(15, 2)),
|    ВТ_Пол.Контрагент

Функция ВЫРАЗИТЬ позволяет привести числовые значения к одинаковой разрядности, что делает их идентичными для механизма группировки СУБД.

Алгоритм поиска «виновного» поля

Если вы применили все вышеуказанные советы, но строки всё равно не объединяются, выполните следующие шаги для диагностики:

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

Альтернатива: Система компоновки данных (СКД)

Разберем профессиональный подход. Если ваша задача — вывести таблицу, где в колонках стоят периоды, а в строках — контрагенты, ручное написание колонок Сумма1, Сумма2 в запросе является трудоемким и негибким методом. В 1С для этих целей предназначена СКД. В СКД достаточно написать простой запрос, выбирающий детальные записи с полем Период и Сумма. Далее в настройках отчета создается Таблица, где в «Строки» добавляется Контрагент, а в «Колонки» — Период. Система компоновки данных сама выполнит группировку, распределение по столбцам и корректное «схлопывание» всех пустых ячеек без необходимости сложного ручного кодинга в тексте запроса.

← На главную