Работа с табличными данными в 1С:Предприятие часто требует передачи целых таблиц в SQL-запросы как параметров. Это типичная задача при формировании сложных отчетов, аналитических выборок или интеграции с внешними системами. Однако стандартный механизм параметров запроса УстановитьПараметр не поддерживает прямую передачу объектов типа ТаблицаЗначений или ТабличнаяЧасть — только скалярные значения (числа, строки, даты) и массивы.
В этой статье разберем три проверенных способа передачи табличных данных в запросы: через временные таблицы, преобразование в массив структур и использование динамических списков. Каждый метод имеет свои особенности по производительности, синтаксису и ограничениям — вы узнаете, когда какой подход применять, а также как избежать типичных ошибок при работе с большими наборами данных.
Особое внимание уделим недокументированным нюансам взаимодействия 1С и СУБД, которые влияют на скорость выполнения запросов с табличными параметрами. Например, почему передача массива из 10 000 строк может замедлить запрос в 50 раз по сравнению с временной таблицей, и как это обойти.
1. Метод временных таблиц: классический подход с максимальной производительностью
Самый универсальный и эффективный способ — создание временной таблицы в базе данных, заполнение её данными из 1С, а затем использование в запросе. Этот метод работает во всех версиях платформы (включая 8.2 и 8.3) и поддерживается всеми СУБД (Microsoft SQL Server, PostgreSQL, IBM DB2, Oracle).
Основное преимущество: данные передаются на сервер СУБД одним пакетом, что минимизирует сетевой трафик и ускоряет выполнение сложных запросов. Например, при фильтрации по 50 000 строк временная таблица будет работать в 10–100 раз быстрее, чем передача этих данных через параметры.
- ⚡ Плюсы: максимальная скорость, поддержка больших объемов данных (миллионы строк), совместимость со всеми СУБД.
- ⚠️ Минусы: требует прав на создание временных таблиц, сложнее в реализации для новичков.
- 🔧 Когда использовать: для отчетов с большими выборками, интеграции с внешними системами, сложных аналитических запросов.
Пример кода для создания временной таблицы и её использования в запросе:
// 1. Создаем временную таблицу
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Ссылка,
| Товары.Артикул КАК Артикул
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| Справочник.Товары КАК Товары
|ГДЕ
| Товары.ПометкаУдаления = ЛОЖЬ";
Запрос.Выполнить;
// 2. Заполняем её данными из таблицы значений
ТаблицаТоваров = ПолучитьТаблицуТоваров; // Ваша таблица значений
Для Каждого Строка Из ТаблицаТоваров Цикл
Запрос = Новый Запрос;
Запрос.Текст =
"ВСТАВИТЬ В ВТ_Товары (Ссылка, Артикул)
|ЗНАЧЕНИЯ (&Ссылка, &Артикул)";
Запрос.УстановитьПараметр("Ссылка", Строка.Ссылка);
Запрос.УстановитьПараметр("Артикул", Строка.Артикул);
Запрос.Выполнить;
КонецЦикла;
// 3. Используем временную таблицу в основном запросе
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_Товары.Ссылка КАК Товар,
| ДвиженияОстатков.КоличествоОстаток КАК Остаток
|ИЗ
| ВТ_Товары КАК ВТ_Товары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК ДвиженияОстатков
| ПО ВТ_Товары.Ссылка = ДвиженияОстатков.Товар
|ГДЕ
| ДвиженияОстатков.Период = &ДатаОтчета";
Запрос.УстановитьПараметр("ДатаОтчета", ТекущаяДата);
Результат = Запрос.Выполнить;
⚠️ Внимание: В PostgreSQL и IBM DB2 временные таблицы автоматически удаляются после завершения сеанса, а в Microsoft SQL Server — только при явном вызове УНИЧТОЖИТЬ ВТ_ИмяТаблицы. Всегда очищайте временные таблицы после использования, чтобы избежать накопления мусора в базе.
2. Преобразование таблицы в массив структур: простой, но ограниченный способ
Если временные таблицы недоступны (например, в файловом варианте 1С или при ограниченных правах пользователя), можно преобразовать таблицу значений в массив структур и передать его как параметр. Этот метод проще в реализации, но имеет жесткие ограничения:
- 📌 Ограничение 1: Максимальный размер параметра — 4 000 символов (в 1С:Предприятие 8.3.20+ расширен до 10 000). При превышении возникнет ошибка
Длина параметра превышает допустимое значение. - 📌 Ограничение 2: Производительность падает экспоненциально при росте объема данных. Например, обработка 1 000 строк может занять в 10 раз дольше, чем при использовании временных таблиц.
- 🔄 Когда применять: Для небольших таблиц (до 100–200 строк) в простых запросах.
Пример кода:
ТаблицаТоваров = ПолучитьТаблицуТоваров;
МассивСтруктур = Новый Массив;
// Преобразуем таблицу в массив структур
Для Каждого Строка Из ТаблицаТоваров Цикл
СтруктураСтроки = Новый Структура;
СтруктураСтроки.Вставить("Ссылка", Строка.Ссылка);
СтруктураСтроки.Вставить("Артикул", Строка.Артикул);
МассивСтруктур.Добавить(СтруктураСтроки);
КонецЦикла;
// Передаем массив как параметр
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Артикул КАК Артикул,
| Товары.Наименование КАК Наименование
|ИЗ
| Справочник.Товары КАК Товары
|ГДЕ
| Товары.Артикул В (&Артикулы)";
Запрос.УстановитьПараметр("Артикулы", МассивСтруктур.ВыгрузитьКолонку("Артикул"));
Результат = Запрос.Выполнить;
Если нужно передать несколько колонок, используйте функцию ЗначениеВМассивJSON (доступна с версии 8.3.18). Она позволяет сериализовать структуру в строку и избежать ограничения на длину параметра. Пример: Запрос.УстановитьПараметр("Данные", ЗначениеВМассивJSON(МассивСтруктур));
3. Динамические списки: альтернатива для отчетов и выборок
Если задача сводится к фильтрации данных по значениям из таблицы, можно использовать динамические списки. Этот метод не требует создания временных таблиц и работает даже в управляемых формах. Подходит для:
- 📊 Отображения данных в отчетах с фильтрами.
- 🔍 Поиска по справочникам с динамической выборкой.
- 📋 Формирования списков документов по критериям из таблицы.
Пример настройки динамического списка с фильтрацией по таблице значений:
// Создаем динамический список
ДинамическийСписок = Документы.ЗаказыПокупателей.СоздатьМенеджерВыбора;
ДинамическийСписок.ПараметрыВыбора.Отбор.Добавить("Дата", Тип("ДатаНачало"), Значение(НачалоДня(ТекущаяДата)));
// Добавляем отбор по товарам из таблицы
ТаблицаТоваров = ПолучитьТаблицуТоваров;
Для Каждого Строка Из ТаблицаТоваров Цикл
ДинамическийСписок.ПараметрыВыбора.Отбор.Добавить("Товары.Ссылка", Тип("Равно"), Строка.Ссылка, Истина);
КонецЦикла;
// Получаем результат
Результат = ДинамическийСписок.ВыполнитьВыбор;
⚠️ Внимание: Динамические списки не поддерживают сложные соединения таблиц (например, LEFT JOIN с несколькими условиями). Для таких случаев используйте временные таблицы или массивы структур.
4. Сравнение методов: какой выбрать для вашей задачи
Выбор метода зависит от объема данных, типа СУБД и требований к производительности. В таблице ниже — сравнение ключевых характеристик:
| Критерий | Временные таблицы | Массив структур | Динамические списки |
|---|---|---|---|
| Макс. объем данных | Неограниченно | До 10 000 строк* | До 10 000 строк |
| Производительность | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| Сложность реализации | Средняя | Низкая | Низкая |
| Поддержка в файловом варианте | Нет | Да | Да |
| Требуемые права | CREATE TABLE | Нет | Нет |
* В версиях 1С ниже 8.3.20 ограничение — 4 000 символов на параметр.
Для запросов с более чем 1 000 строк всегда отдавайте предпочтение временным таблицам. Массивы структур и динамические списки подходят только для небольших наборов данных или простых фильтров.
5. Оптимизация запросов с табличными параметрами
Даже при правильном выборе метода передачи таблицы в запрос можно столкнуться с проблемами производительности. Вот 5 практических советов для оптимизации:
- Индексируйте временные таблицы. Если временная таблица используется в соединениях (
JOIN), добавьте индекс по ключевым полям:СОЗДАТЬ ИНДЕКС IX_ВТ_Товары_Ссылка НА ВТ_Товары(Ссылка) - Используйте пакетную вставку. Вместо цикла по строкам загружайте данные пакетами по 1 000–5 000 строк:
Запрос.Текст ="ВСТАВИТЬ В ВТ_Товары ВЫБРАТЬ * ИЗ &Таблица";Запрос.УстановитьПараметр("Таблица", ТаблицаТоваров.Выгрузить);
- Ограничивайте колонки. Передавайте в запрос только необходимые поля таблицы, чтобы уменьшить объем данных.
- Избегайте
LIKEс параметрами. Фильтрация по шаблону (ПОДОБНО) с табличными параметрами работает крайне медленно. - Тестируйте на реальных данных. Производительность может отличаться в 100 раз в зависимости от СУБД и версии 1С.
Используются ли индексы на временных таблицах?|
Передаются только необходимые колонки?|
Данные загружаются пакетами, а не построчно?|
Отсутствуют операции LIKE/PODOBNO с параметрами?|
Тестировался ли запрос на объеме данных > 10 000 строк?
-->
6. Типичные ошибки и как их избежать
При работе с таблицами в запросах разработчики часто сталкиваются с одними и теми же проблемами. Вот топ-3 ошибки и способы их решения:
- 🚫 Ошибка 1:
Поле объекта не обнаружено (&Параметр)Причина: Несовпадение имен колонок в таблице значений и параметрах запроса.
Решение: Проверьте регистр и названия колонок. В 1С имена параметров чувствительны к регистру!
- 🚫 Ошибка 2:
Превышен максимальный размер параметраПричина: Передача слишком большого массива структур (более 10 000 строк).
Решение: Разбейте данные на части или используйте временные таблицы.
- 🚫 Ошибка 3: Запрос выполняется крайне медленно без видимых причин.
Причина: Отсутствие индексов на временных таблицах или неоптимальный план выполнения.
Решение: Проанализируйте план запроса в Консоли запросов 1С (меню
Все функции → План запроса).
Как включить отображение плана запроса в 1С 8.3
1. Откройте консоль запросов (Ctrl+Shift+Q).
2. В меню выберите Все функции → Показать план запроса.
3. Выполните запрос — план отобразится в отдельной вкладке.
4. Обратите внимание на узкие места (операции TABLE SCAN или NESTED LOOP без индексов).
7. Примеры реальных задач с табличными параметрами
Рассмотрим два практических сценария, где передача таблицы в запрос решаетчные бизнес-задачи.
Задача 1: Формирование отчета по остаткам товаров из Excel.
Пользователь загружает в 1С таблицу с артикулами из Excel и хочет получить остатки только по этим товарам. Решение:
// 1. Чтение данных из Excel
ТаблицаАртикулов = ПрочитатьExcelФайл(ПутьКФайлу);
// 2. Создание временной таблицы
Запрос = Новый Запрос;
Запрос.Текст ="ВЫБРАТЬ Артикул ПОМЕСТИТЬ ВТ_Артикулы ИЗ &Таблица";
Запрос.УстановитьПараметр("Таблица", ТаблицаАртикулов);
Запрос.Выполнить;
// 3. Запрос остатков
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_Артикулы.Артикул КАК Артикул,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| ВТ_Артикулы КАК ВТ_Артикулы
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки
| ПО ВТ_Артикулы.Артикул = Остатки.Товар.Артикул";
Результат = Запрос.Выполнить;
Задача 2: Синхронизация данных с внешней системой.
При интеграции с 1С:EDT или REST API часто требуется передать список измененных объектов. Пример для документов ЗаказПокупателя:
// 1. Получаем список измененных заказов из внешней системы
СписокЗаказов = ПолучитьИзмененныеЗаказыИзAPI;
// 2. Преобразуем в массив GUID
МассивGUID = Новый Массив;
Для Каждого Заказ Из СписокЗаказов Цикл
МассивGUID.Добавить(Заказ.УникальныйИдентификатор);
КонецЦикла;
// 3. Запрашиваем данные по этим GUID
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказы.Ссылка КАК Ссылка,
| Заказы.Номер КАК Номер
|ИЗ
| Документ.ЗаказПокупателя КАК Заказы
|ГДЕ
| Заказы.УникальныйИдентификатор В (&GUIDs)";
Запрос.УстановитьПараметр("GUIDs", МассивGUID);
Результат = Запрос.Выполнить;
FAQ: Частые вопросы по работе с таблицами в запросах 1С
Можно ли передать табличную часть документа напрямую в запрос?
Нет, табличные части (как и таблицы значений) нельзя передать напрямую. Их нужно предварительно преобразовать во временную таблицу или массив структур. Для табличных частей удобно использовать метод Выгрузить:
ТабличнаяЧасть = Документ.Товары;
МассивДанных = ТабличнаяЧасть.Выгрузить;
Как передать таблицу с более чем 10 000 строк в файловом варианте 1С?
В файловом варианте временные таблицы недоступны, а массив структур ограничен 10 000 элементами. Решения:
- Разбить данные на части и выполнить несколько запросов.
- Использовать внешние обработки с SQLite для промежуточного хранения.
- Оптимизировать задачу так, чтобы фильтрация происходила на стороне 1С, а не в запросе.
Почему запрос с временной таблицей работает медленно?
Частые причины:
- Отсутствуют индексы на временной таблице.
- Данные загружаются построчно, а не пакетами.
- СУБД не использует оптимальный план выполнения (проверьте в
План запроса). - Временная таблица создается в транзакции, что блокирует другие процессы.
Решение: добавьте индексы, используйте пакетную вставку и анализируйте план запроса.
Можно ли использовать табличные параметры в управляемых формах?
Да, но с ограничениями:
- Временные таблицы требуют серверного контекста (используйте в модуле объекта или на сервере).
- Массивы структур можно передавать и на клиенте, но объем данных ограничен.
- Для динамических списков в управляемых формах используйте метод
УстановитьПараметрменеджера выбора.
Как передать таблицу в запрос с группировкой (GROUP BY)?
Пример запроса с группировкой по данным из временной таблицы:
// 1. Создаем временную таблицу с категориями товаров
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Категория КАК Категория,
| СУММА(Количество) КАК ОбщееКоличество
|ИЗ
| ВТ_Товары КАК ВТ_Товары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки
| ПО ВТ_Товары.Ссылка = Остатки.Товар
|СГРУППИРОВАТЬ ПО
| Категория";