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

В этой статье мы разберём 5 способов свертки таблицы значений с условием — от простых (с использованием встроенных методов) до сложных (с применением запросов и временных таблиц). Особое внимание уделим оптимизации производительности при работе с большими объёмами данных, так как неграмотная реализация может привести к зависанию системы. Все примеры приведены для платформ 1С 8.3 и 8.2 с учётом их особенностей.

Если вы ранее сталкивались с ошибками вроде "Поле не найдено в таблице значений" или "Недопустимый тип данных" при попытке свертки — здесь вы найдёте решения. А для новичков мы подготовили пошаговые инструкции с разбором каждого этапа.

1. Стандартный метод Свернуть() с предварительной фильтрацией

Самый очевидный способ — сначала отфильтровать таблицу значений по условию, а затем применить метод Свернуть(). Этот подход подходит для небольших наборов данных (до 10 000 строк), так как не требует сложных конструкций.

Алгоритм действий:

  • 🔍 Отфильтруйте таблицу значений с помощью метода ВыбратьСтроки() или цикла Для Каждого, оставив только строки, соответствующие условию.
  • 📊 Сверните отфильтрованную таблицу по нужным полям (например, по "Контрагент" или "Номенклатура").
  • 📝 Проверьте результат: метод Свернуть() автоматически суммирует числовые поля (например, "Количество" или "Сумма").

Пример кода:

// Исходная таблица значений

ТЗ = Новый ТаблицаЗначений;

ТЗ.Колонки.Добавить("Контрагент");

ТЗ.Колонки.Добавить("Номенклатура");

ТЗ.Колонки.Добавить("Количество");

ТЗ.Колонки.Добавить("Сумма");

// Заполняем данными (пример)

Для Сч = 1 По 5 Цикл

Строка = ТЗ.Добавить();

Строка.Контрагент = "Контрагент_" + Сч;

Строка.Номенклатура = "Товар_" + (Сч % 2 + 1);

Строка.Количество = Сч * 10;

Строка.Сумма = Сч * 1000;

КонецЦикла;

// Фильтруем по условию (например, только товары с чётным номером)

ФильтрованнаяТЗ = ТЗ.ВыбратьСтроки(Новый Структура("Номенклатура", "Товар_2"));

// Свертываем по полю "Контрагент"

Результат = ФильтрованнаяТЗ.Свернуть("Контрагент");

⚠️ Внимание: Метод ВыбратьСтроки() создаёт новую таблицу значений, что может потребовать дополнительной памяти при большом объёме данных. Для таблиц свыше 50 000 строк лучше использовать Запрос или Объект.Выбрать().
📊 Какой метод свертки вы используете чаще?
Стандартный Свернуть()
Запросы 1С
Временные таблицы
Циклы с ручной обработкой
Другой

2. Свертка с использованием запроса 1С

Если данные хранятся в базе (например, в регистрах или документах), оптимальнее выполнить свертку непосредственно в запросе. Это снизит нагрузку на память и ускорит обработку. Метод подходит для работы с большими объёмами (100 000+ строк).

Преимущества подхода:

  • Высокая производительность: обработка происходит на стороне СУБД, а не в памяти клиента.
  • 🔧 Гибкость условий: можно применять сложные фильтры с ГДЕ, И, ИЛИ.
  • 📈 Агрегация данных: поддерживаются функции СУММА(), МАКСИМУМ(), КОЛИЧЕСТВО().

Пример запроса для свертки остатков номенклатуры по складам с условием по дате:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| ОстаткиНоменклатуры.Номенклатура КАК Номенклатура,

| ОстаткиНоменклатуры.Склад КАК Склад,

| СУММА(ОстаткиНоменклатуры.КоличествоОстаток) КАК Количество

|ИЗ

| РегистрНакопления.ОстаткиНоменклатуры КАК ОстаткиНоменклатуры

|ГДЕ

| ОстаткиНоменклатуры.Период = &Дата

| И ОстаткиНоменклатуры.Склад В (&СписокСкладов)

|

|СГРУППИРОВАТЬ ПО

| ОстаткиНоменклатуры.Номенклатура,

| ОстаткиНоменклатуры.Склад";

Запрос.УстановитьПараметр("Дата", ТекущаяДата());

Запрос.УстановитьПараметр("СписокСкладов", МассивСкладов);

РезультатЗапроса = Запрос.Выполнить();

ТаблицаРезультата = РезультатЗапроса.Выгрузить();

⚠️ Внимание: При использовании запросов в 1С:Предприятие 8.2 некоторые функции (например, РАЗЛИЧНЫЕ) могут работать иначе, чем в 8.3. Всегда тестируйте запрос в нужной версии платформы.

1. Определите источник данных (регистр, документ, справочник)

2. Составьте список полей для группировки (СГРУППИРОВАТЬ ПО)

3. Добавьте условия фильтрации (ГДЕ)

4. Укажите агрегируемые поля (СУММА, КОЛИЧЕСТВО и т.д.)

5. Выгрузите результат в таблицу значений-->

3. Ручная свертка в цикле (для сложных условий)

Когда стандартные методы не подходят (например, нужно свернуть по динамическому условию или применить нестандартную логику агрегации), приходится писать ручную обработку в цикле. Этот способ самый трудоёмкий, но даёт максимальную гибкость.

Типичные сценарии для ручной свертки:

  • 🔄 Динамические условия: когда критерий группировки зависит от данных в других полях (например, свернуть по "Контрагент + Дата" только для строк с отрицательным остатком).
  • 📉 Нестандартная агрегация: например, не сумма, а средневзвешенное значение или медиана.
  • 🔗 Связанные данные: когда нужно свернуть с учётом информации из других таблиц или справочников.

Пример кода для свертки по двум полям с условием:

// Исходная таблица

ТЗ = ПолучаемТаблицуЗначений(); // Предполагаем, что данные уже загружены

// Результирующая таблица для свертки

РезультатТЗ = Новый ТаблицаЗначений;

РезультатТЗ.Колонки.Добавить("Контрагент");

РезультатТЗ.Колонки.Добавить("Номенклатура");

РезультатТЗ.Колонки.Добавить("Сумма");

// Временный словарь для хранения промежуточных данных

Словарь = Новый Соответствие;

// Проходим по исходной таблице

Для Каждого Строка Из ТЗ Цикл

// Проверяем условие (например, только положительные суммы)

Если Строка.Сумма > 0 Тогда

Ключ = Строка.Контрагент + "|" + Строка.Номенклатура;

Если Словарь.СодержитКлюч(Ключ) Тогда

// Обновляем существующую запись

ТекущаяСумма = Словарь[Ключ].Сумма + Строка.Сумма;

Словарь[Ключ].Сумма = ТекущаяСумма;

Иначе

// Добавляем новую запись

НоваяСтрока = РезультатТЗ.Добавить();

НоваяСтрока.Контрагент = Строка.Контрагент;

НоваяСтрока.Номенклатура = Строка.Номенклатура;

НоваяСтрока.Сумма = Строка.Сумма;

Словарь.Вставить(Ключ, НоваяСтрока);

КонецЕсли;

КонецЕсли;

КонецЦикла;

💡

Для ускорения ручной свертки используйте Соответствие (словарь) вместо поиска по таблице значений — это сокращает время обработки в 10-100 раз.

4. Свертка с использованием временных таблиц

Для обработки очень больших таблиц (100 000+ строк) целесообразно использовать ВременныеТаблицы. Этот метод сочетает гибкость запросов с возможностью работы с промежуточными данными.

Преимущества временных таблиц:

  • 🚀 Производительность: данные хранятся в СУБД, а не в памяти клиента.
  • 🔄 Многоэтапная обработка: можно выполнять несколько запросов к одной временной таблице.
  • 🔒 Изоляция данных: временные таблицы доступны только в текущей сессии.

Пример использования:

// Создаём временную таблицу и загружаем данные

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Документ.Контрагент КАК Контрагент,

| Документ.Номенклатура КАК Номенклатура,

| Документ.Количество КАК Количество

|ПОМЕСТИТЬ ВТ_Данные

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Документ

|ГДЕ

| Документ.Дата МЕЖДУ &ДатаНачала И &ДатаКонца";

Запрос.УстановитьПараметр("ДатаНачала", НачалоМесяца(ТекущаяДата()));

Запрос.УстановитьПараметр("ДатаКонца", КонецМесяца(ТекущаяДата()));

Запрос.Выполнить();

// Свертка по временной таблице

ЗапросСвертки = Новый Запрос;

ЗапросСвертки.Текст =

"ВЫБРАТЬ

| ВТ_Данные.Контрагент КАК Контрагент,

| ВТ_Данные.Номенклатура КАК Номенклатура,

| СУММА(ВТ_Данные.Количество) КАК ИтогоКоличество

|ИЗ

| ВТ_Данные КАК ВТ_Данные

|ГДЕ

| ВТ_Данные.Количество > 0

|СГРУППИРОВАТЬ ПО

| ВТ_Данные.Контрагент,

| ВТ_Данные.Номенклатура";

Результат = ЗапросСвертки.Выполнить();

ТаблицаРезультата = Результат.Выгрузить();

⚠️ Внимание: Временные таблицы автоматически удаляются после завершения сессии, но их можно явно очистить командой УдалитьВременныеТаблицы(), если они больше не нужны. Это освободит ресурсы СУБД.

5. Оптимизация производительности при свертке

Независимо от выбранного метода, свертка больших таблиц может тормозить систему. Вот ключевые рекомендации по оптимизации:

Проблема Решение Применимо к
Долгая обработка в цикле Замените НайтиСтроки() на Соответствие (словарь) Ручная свертка
Переполнение памяти Используйте ВременныеТаблицы или запросы Таблицы > 50 000 строк
Медленные запросы Добавьте индексы на поля группировки в базе данных Запросы к регистрам
Ошибки типов данных Проверяйте типы полей перед сверткой (например, ТипЗнч()) Все методы

Дополнительные советы:

  • 📌 Индексы: Убедитесь, что поля, по которым выполняется группировка, проиндексированы в базе данных. Это ускорит выполнение запросов.
  • 🧹 Очистка данных: Перед сверткой удаляйте ненужные колонки из таблицы значений — это уменьшит объём обрабатываемых данных.
  • Асинхронность: Для длительных операций используйте ФоновоеЗадание, чтобы не блокировать интерфейс пользователя.
Как проверить индексы в 1С?

1. Откройте консоль запросов (Отладка → Запросы → Консоль запросов).

2. Выполните запрос ВЫБРАТЬ ИНФОРМАЦИЯОБИНДЕКСАХ().

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

Типичные ошибки и их решения

При свертке таблиц значений разработчики часто сталкиваются с типовыми ошибками. Разберём самые распространённые:

  1. Ошибка: "Поле не найдено в таблице значений"

    Причина: Указано несуществующее поле в методе Свернуть() или запросе.

    Решение: Проверьте названия колонок с учётом регистра. В 1С имена полей чувствительны к регистру!

  2. Ошибка: "Недопустимый тип данных"

    Причина: П попытка сложить строки с числами (например, поле "Количество" имеет тип Строка вместо Число).

    Решение: Преобразуйте типы заранее:

    ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

  3. Ошибка: "Слишком много данных для обработки"

    Причина: Попытка свернуть таблицу с миллионом строк в памяти клиента.

    Решение: Используйте ВременныеТаблицы или разбейте данные на части.

💡

Всегда проверяйте типы данных полей перед сверткой — это избавит от 80% ошибок.

FAQ: Частые вопросы по свертке таблиц значений

Можно ли свернуть таблицу значений по нескольким полям одновременно?

Да, метод Свернуть() поддерживает массив полей для группировки. Пример:

Результат = ТЗ.Свернуть(Новый Массив("Контрагент", "Номенклатура"));

Аналогично в запросе используйте несколько полей в СГРУППИРОВАТЬ ПО.

Как свернуть таблицу с условием по дате?

Добавьте фильтрацию по дате перед сверткой:

  1. Для таблицы значений: ТЗ.ВыбратьСтроки(Новый Структура("Дата", НачалоМесяца(ТекущаяДата()))).
  2. В запросе: ГДЕ Документ.Дата = &ТекущаяДата.
Почему после свертки пропадают некоторые строки?

Скорее всего, строки не удовлетворяли условию фильтрации или имели пустые значения в полях группировки. Проверьте:

  • Условия в ВыбратьСтроки() или ГДЕ.
  • Наличие NULL в ключевых полях (используйте ЕСТЬNULL в запросах).
Как свернуть таблицу с учётом иерархии справочников?

Для иерархической свертки (например, по группам номенклатуры) используйте:

  1. В запросе: СГРУППИРОВАТЬ ПО ИЕРАРХИЯ(Номенклатура.Ссылка).
  2. В коде: рекурсивный обход справочника с ручной агрегацией.

Пример для запроса:

СГРУППИРОВАТЬ ПО

ИЕРАРХИЯ(Номенклатура.Ссылка) КАК ГруппаНоменклатуры

Можно ли отменить свертку таблицы значений?

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

КопияТЗ = ТЗ.Скопировать();

Результат = ТЗ.Свернуть("Поле");