Язык запросов 1С

1С: обход результата запроса по группировкам и деталям

Коротко

Добавьте в запрос ИТОГИ СУММА(Количество) ПО Группа и получите выборку через ОбходРезультатаЗапроса.ПоГруппировкам. После позиционирования на группе методом Следующий() вызовите её Выбрать(ОбходРезультатаЗапроса.Прямой), чтобы пройти детали именно этой группы.

Если в итогах есть ОБЩИЕ, обход без явно указанной группировки начинается с общего итога. Чтобы спуститься ниже, создайте вложенную выборку от этой записи.

1С: обход результата запроса по группировкам — минимальный запрос

Полный запрос ниже создаёт три строки из литералов: А/X/2, А/Y/3, Б/Z/4. Он не читает документы, справочники и регистры. Вставьте его в Консоль запросов; для программного обхода используйте самостоятельные BSL-фрагменты ниже. Длинная вторая строка — только подготовка собственных данных.

ВЫБРАТЬ Д.Группа, Д.Позиция, Д.Количество
ИЗ (ВЫБРАТЬ "А" КАК Группа, "X" КАК Позиция, 2 КАК Количество ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "А", "Y", 3 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "Б", "Z", 4) КАК Д
УПОРЯДОЧИТЬ ПО Группа, Позиция
ИТОГИ СУММА(Количество) ПО Группа

В секции ВЫБРАТЬ число не агрегируется: исходные детали сохраняются. Сумма считается в ИТОГИ: для группы А — 5, для Б — 4. УПОРЯДОЧИТЬ ПО Группа, Позиция задаёт сортировку по полям результата. Ниже показан ожидаемый состав сообщений; порядок групп при обходе итогов этим примером не доказан.

Группы и вложенные детали без ОБЩИЕ

Место вставки — тело серверной процедуры общего модуля либо серверная Консоль кода. В модуле управляемой формы поместите тело в процедуру с директивой &НаСервереБезКонтекста и вызовите её штатным способом. Реквизиты формы, параметры и типовые общие модули не нужны. Не выполняйте этот код непосредственно в тонком или веб-клиенте.

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ Д.Группа, Д.Позиция, Д.Количество
    |ИЗ (ВЫБРАТЬ ""А"" КАК Группа, ""X"" КАК Позиция, 2 КАК Количество ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ""А"", ""Y"", 3 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ""Б"", ""Z"", 4) КАК Д
    |УПОРЯДОЧИТЬ ПО Группа, Позиция
    |ИТОГИ СУММА(Количество) ПО Группа";
Результат = Запрос.Выполнить();

Группы = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока Группы.Следующий() Цикл
    Сообщить("Группа " + Группы.Группа + ": " + Строка(Группы.Количество));
    Детали = Группы.Выбрать(ОбходРезультатаЗапроса.Прямой);
    Пока Детали.Следующий() Цикл
        Сообщить("  " + Детали.Позиция + ": " + Строка(Детали.Количество));
    КонецЦикла;
КонецЦикла;
РезультатЗапроса.Выбрать / ВыборкаИзРезультатаЗапроса.Выбрать
ТипОбходаОбходРезультатаЗапроса; по умолчанию Прямой
ГруппировкиСтрока имён через запятую; пропуск выбирает следующую группировку ИТОГИ, пустая строка — детали
ГруппировкиДляЗначенийГруппировокСтрока; «Все» расширяет набор значений, здесь параметр не задан
→ ВыборкаИзРезультатаЗапроса

Группы берутся из результата; детали — из текущей записи выборки группы.

Ожидаемый состав пяти сообщений для этих литералов (целые числа меньше 10), не журнал платформы. Порядок А/Б и X/Y показан иллюстративно; детали выводятся после своей группы:

Группа А: 5
  X: 2
  Y: 3
Группа Б: 4
  Z: 4

Первый Выбрать() вызывается у РезультатЗапроса. Второй — у ВыборкаИзРезультатаЗапроса внутри цикла после успешного Следующий(). Это разные получатели одного имени метода. Создание выборки ещё не позиционирует её на строке.

ОБЩИЕ: дополнительная выборка верхнего итога

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

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ Д.Группа, Д.Позиция, Д.Количество
    |ИЗ (ВЫБРАТЬ ""А"" КАК Группа, ""X"" КАК Позиция, 2 КАК Количество ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ""А"", ""Y"", 3 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ""Б"", ""Z"", 4) КАК Д
    |УПОРЯДОЧИТЬ ПО Группа, Позиция
    |ИТОГИ СУММА(Количество) ПО ОБЩИЕ, Группа";
Результат = Запрос.Выполнить();

ОбщийИтог = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Если ОбщийИтог.Следующий() Тогда
    Сообщить("Всего: " + Строка(ОбщийИтог.Количество));
    Группы = ОбщийИтог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    Пока Группы.Следующий() Цикл
        Сообщить("Группа " + Группы.Группа + ": " + Строка(Группы.Количество));
        Детали = Группы.Выбрать(ОбходРезультатаЗапроса.Прямой);
        Пока Детали.Следующий() Цикл
            Сообщить("  " + Детали.Позиция + ": " + Строка(Детали.Количество));
        КонецЦикла;
    КонецЦикла;
КонецЕсли;
ВыборкаИзРезультатаЗапроса.Выбрать
ТипОбходаОбходРезультатаЗапроса; по умолчанию Прямой
ГруппировкиСтрока имён через запятую; пропуск выбирает следующую группировку ИТОГИ, пустая строка — детали
ГруппировкиДляЗначенийГруппировокСтрока; «Все» расширяет набор значений, здесь параметр не задан
→ ВыборкаИзРезультатаЗапроса

Общий итог → группы → детали. Вложенные выборки создаются от текущего родителя.

Ожидаемый состав шести сообщений, не журнал платформы. «Всего: 9» выводится перед вложенным циклом по коду; взаимный порядок групп и деталей ниже показан иллюстративно, а не подтверждён запуском. Детали выводятся после своей группы.

Всего: 9
Группа А: 5
  X: 2
  Y: 3
Группа Б: 4
  Z: 4

Почему видна только верхняя группа

Проверьте порядок после ПО в секции ИТОГИ. Без ОБЩИЕ верхний уровень здесь — А и Б; с ОБЩИЕ — единственная запись общего итога. Один внешний цикл не раскрывает все уровни автоматически.

Если добавить ещё одно поле группировки после Группа, для его итогов потребуется ещё один вложенный обход ПоГруппировкам. Прямой обход от текущей группы нужен для деталей, а не для вывода промежуточных итоговых строк.

Имя группировки можно явно передать вторым параметром Выбрать() и выбрать нужный уровень. Наличие ОБЩИЕ не делает этот приём ошибочным: официальная статья ИТС использует именованную группировку напрямую от результата. В примерах выше выбран последовательный обход всех уровней без пропуска общего итога.

Для диагностики в Консоли кода попросите агента сопоставить порядок ИТОГИ и получателей вложенных Выбрать(). Передайте обезличенный текст запроса и маленький набор собственных данных; для проверки структуры не требуется читать рабочие документы.

Параметры Выбрать и правильное имя перечисления

Сигнатура у обоих получателей: Выбрать(<ТипОбхода>, <Группировки>, <ГруппировкиДляЗначенийГруппировок>); все параметры необязательны. ТипОбхода — имя параметра, а перечисление называется ОбходРезультатаЗапроса, не «ТипОбходаРезультатаЗапроса».

  • Прямой — обход детальных записей; это значение по умолчанию.
  • ПоГруппировкам — обход итоговых группировок, предусмотренных запросом.
  • Пропущенный второй параметр означает следующую группировку из ИТОГИ. Явная пустая строка означает детальные записи: эти случаи нельзя отождествлять.
  • Третий параметр «Все» нужен, например, для полного набора колонок кросс-отчёта, а не для обычной детализации текущей группы. В наших примерах он не задан: расширять набор значений незачем.

Группировки итогов не равны иерархии справочника. У примеров строковые ключи, поэтому отдельный режим обхода иерархии ссылочных данных не нужен.

ИТОГИ не заменяет СГРУППИРОВАТЬ ПО

При СГРУППИРОВАТЬ ПО Группа и сумме в SELECT две строки А превращаются в одну агрегированную запись; исходных X и Y в таком результате уже нет. ИТОГИ нашего запроса оставляет X и Y деталями и добавляет сумму А отдельным уровнем. Обход не способен восстановить строки, которые запрос заранее свернул.

Здесь решается именно программный обход выборок. Получение таблицы или дерева значений — отдельный сценарий выгрузки результата запроса; настройки итогов СКД в этот рецепт не входят.

Частые ошибки при обходе по группировкам

  • Нет ИТОГИ в запросе. Режим обхода сам не добавляет отсутствующие группировки; задайте их в тексте.
  • Чтение поля до Следующий(). Сначала позиционируйте выборку, затем обращайтесь к полям или создавайте вложенную выборку.
  • Каждый раз берут детали от Результат. Так получается общий набор деталей вместо подчинённого: получателем должен быть текущий узел группы.
  • Остановились на ОБЩИЕ. Для групп и деталей нужны вложенные выборки.
  • Сложили общую сумму, суммы групп и детали. Это повторный учёт одних данных; для расчёта выбирайте один нужный уровень, не суммируйте все уровни вместе.
  • Перенесли серверный запрос в клиентский обработчик. Объекты запроса и выборки в тонком и веб-клиенте недоступны; выполняйте весь обход на сервере.

Частые вопросы

Почему обход по группировкам показывает только верхнюю группу?

Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) с пропущенной группировкой открывает следующий уровень ИТОГИ. При ПО ОБЩИЕ, Группа сверху находится общий итог. После Следующий() получите вложенную выборку от текущей записи.

Нужно ли ОБЩИЕ для обхода результата по группировкам?

Нет. ИТОГИ СУММА(Количество) ПО Группа достаточно для итогов каждой группы. ОБЩИЕ добавляет общий итог всей выборки и дополнительный верхний уровень при обходе без явно заданного имени группировки.

Чем ИТОГИ отличается от СГРУППИРОВАТЬ ПО?

СГРУППИРОВАТЬ ПО объединяет исходные строки в агрегированные записи. ИТОГИ добавляет итоговые уровни к результату, сохраняя его детальные записи. Для обхода итогов используется ОбходРезультатаЗапроса.ПоГруппировкам.

Тарифы

ИИ Консоль запросов 1С

Лайт

Бесплатно

Для ознакомления с возможностями

  • Все функции бесплатно на 2 дня +2 дня за подписку на Telegram или Max
  • Полный набор инструментов без урезаний
  • Без ввода карты
Начать бесплатно

Старт

Популярный выбор
990 руб. в месяц
≈ 5 млн токенов

Для индивидуального использования

Выбрать тариф

Продвинутый

3900 руб. в месяц
≈ 19,5 млн токенов

Для интенсивного использования или команд

Выбрать тариф