Работа с языком запросов 1С:Предприятие часто требует не просто выборки данных из существующих таблиц базы данных, а манипулирования наборами значений, сформированными непосредственно в коде. Для этих целей разработчики используют объект ТаблицаЗначений. Это мощный инструмент, позволяющий передавать списки параметров, фильтров или временных данных прямо в тело запроса, минуя необходимость создания временных таблиц на диске или использования сложных конструкций с UNION.
Внедрение таблицы значений в текст запроса открывает возможности для динамической фильтрации, когда количество условий заранее неизвестно. Например, вам нужно отобрать документы только по определенному списку контрагентов, который пользователь выбрал в интерфейсе. Вместо того чтобы формировать гигантское условие ИЛИ Контрагент = Значение1 ИЛИ Контрагент = Значение2, гораздо эффективнее и чище передать этот список как параметр типа ТаблицаЗначений. Это не только упрощает чтение кода, но и часто положительно сказывается на производительности исполнения запроса сервером.
Однако, несмотря на очевидные преимущества, синтаксис работы с этим объектом имеет свои нюансы, которые могут сбить с толку начинающего разработчика. Неправильное описание полей или несоответствие типов данных могут привести к ошибке выполнения или, что хуже, к некорректным результатам выборки. В этой статье мы подробно разберем механику вставки таблицы значений, рассмотрим типичные ошибки и узнаем, как правильно описывать структуру временного набора данных внутри текста запроса.
Синтаксис описания таблицы значений в тексте запроса
Чтобы использовать таблицу значений в запросе, необходимо сначала объявить её в секции параметров. Это делается с помощью ключевого слова ПАРАМЕТРЫ, за которым следует имя переменной и описание её типа. Для таблицы значений синтаксис требует указания структуры колонок. Вы должны перечислить имена полей и их типы данных в круглых скобках. Если вы забудете описать структуру, система не поймет, как интерпретировать переданные данные, и выдаст ошибку синтаксиса.
Рассмотрим базовый пример объявления. Допустим, нам нужно передать список идентификаторов номенклатуры. В тексте запроса это будет выглядеть следующим образом:
ВЫБРАТЬ
Номенклатура.Ссылка,
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В (&СписокНоменклатуры)
ПАРАМЕТРЫ
&СписокНоменклатуры ТАБЛИЦА(
Ссылка Ссылка.Номенклатура
)
Обратите внимание на конструкцию ТАБЛИЦА(...). Внутри неё мы указываем имя колонки (Ссылка) и её тип (Ссылка.Номенклатура). Имя колонки в описании типа должно совпадать с тем, как вы будете обращаться к ней в условии ГДЕ. Важно понимать, что порядок полей в описании не имеет значения для логики, но для читаемости кода лучше придерживаться последовательности, используемой в дальнейшем тексте запроса. Также стоит отметить, что типы данных должны быть совместимы с теми данными, которые вы фактически поместите в объект ТаблицаЗначений перед выполнением запроса.
⚠️ Внимание: Типы данных в описании таблицы значений должны строго соответствовать типам передаваемых значений. Попытка передать строку в поле, объявленное как Число, вызовет ошибку преобразования типов при выполнении запроса.
Если ваша таблица значений содержит несколько колонок, их нужно перечислить через запятую. Например, если вы фильтруете не только по номенклатуре, но и по складу, описание примет вид: &Параметры ТАБЛИЦА(Номенклатура Ссылка.Номенклатура, Склад Ссылка.Склады). Такой подход позволяет создавать сложные составные условия фильтрации, используя оператор В с составными ключами или соединяя таблицу значений с основными таблицами через ЛЕВОЕ СОЕДИНЕНИЕ.
Используйте краткие и понятные имена для колонок в ТаблицеЗначений. Избегайте имен вроде"Поле1","Колонка2", так как это затрудняет поддержку кода в будущем.
Формирование объекта ТаблицаЗначений в коде 1С
После того как вы описали структуру в тексте запроса, следующим шагом является создание и наполнение самого объекта в программном коде. Для этого используется встроенный метод Новая ТаблицаЗначений. Конструктор таблицы позволяет сразу задать колонки, передав описание структуры в виде строки, что является наиболее распространенным и удобным способом. Строка описания колонок полностью дублирует ту, что вы указали в секции ПАРАМЕТРЫ запроса.
Процесс наполнения таблицы обычно происходит в цикле. Вы можете добавлять строки по одной, используя метод Добавить, или копировать данные из другой таблицы значений или выборки. При добавлении новой строки метод возвращает ссылку на объект строки, свойства которой можно заполнить значениями. Крайне важно следить за тем, чтобы значения присваивались полям с правильными именами, иначе вы получите ошибку"Поле не найдено".
Ниже приведен пример кода на языке 1С, который демонстрирует создание таблицы и передачу её в запрос:
ТЗ_Фильтр = Новая ТаблицаЗначений("Ссылка Ссылка.Номенклатура, Количество Число(15,2)");
Для каждого Элемент из СписокВыбранныхЭлементов Цикл
НоваяСтрока = ТЗ_Фильтр.Добавить;
НоваяСтрока.Ссылка = Элемент.Ссылка;
НоваяСтрока.Количество = Элемент.Количество;
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст ="... (текст запроса с ПАРАМЕТРЫ)...";
Запрос.УстановитьПараметр("СписокНоменклатуры", ТЗ_Фильтр);
Результат = Запрос.Выполнить;
- 📌 Используйте метод
Колонки.Добавить, если структура таблицы формируется динамически и известна только во время выполнения программы. - 🚀 Для повышения производительности при работе с большими объемами данных используйте метод
Загрузитьвместо построчного добавления, если исходные данные уже находятся в массиве или другой таблице. - 🔍 Всегда проверяйте, не пуста ли таблица значений перед установкой параметра, если логика запроса предполагает обработку пустых списков особым образом.
Существует также возможность клонирования структуры таблицы. Если у вас уже есть заполненная таблица значений с нужными колонками, вы можете создать новую пустую таблицу с той же структурой, вызвав конструктор с параметром-источником: Новая ТаблицаЗначений(ИсходнаяТаблица.Колонки). Это удобно, когда нужно создать временный буфер для промежуточных вычислений, сохраняя типы данных оригинала.
☑️ Подготовка данных для запроса
Использование оператора В с таблицей параметров
Наиболее частый сценарий использования таблицы значений — это фильтрация данных с помощью оператора В. Этот оператор позволяет проверить, содержится ли значение поля основной таблицы в наборе значений, переданном через параметр. Синтаксически это выглядит очень лаконично: ГДЕ Поле В (&ПараметрТаблицы). Сервер 1С сам оптимизирует такой запрос, преобразуя его во внутреннее соединение или используя хеш-таблицы для быстрого поиска совпадений.
Особенностью оператора В является то, что он сравнивает значения по всем полям таблицы параметров, если их несколько. Если вы передали таблицу с двумя колонками (например, Номенклатура и Характеристика), то условие В будет истинным только тогда, когда совпадут оба значения одновременно. Это позволяет реализовывать фильтрацию по составным ключам без необходимости склеивать поля в одну строку или использовать сложные логические конструкции с операторами И и ИЛИ.
| Сценарий использования | Количество колонок в ТЗ | Пример условия в запросе |
|---|---|---|
| Фильтрация по списку документов | 1 (Ссылка) | ГДЕ Документ.Ссылка В (&СписокДокументов) |
| Фильтрация по паре"Товар-Склад" | 2 (Товар, Склад) | ГДЕ (Товар, Склад) В (&ПарыТоварСклад) |
| Поиск по диапазонам (через соединение) | 3 (Начало, Конец, Тип) | ЛЕВОЕ СОЕДИНЕНИЕ... НА... |
При использовании оператора В с таблицей значений, содержащей одну колонку, скобки вокруг поля в левой части условия часто опускаются, но при наличии нескольких колонок они обязательны. Например, корректная запись для двух полей: ГДЕ (Таблица.Поле1, Таблица.Поле2) В (&Параметр). Нарушение этого правила приведет к синтаксической ошибке компилятора запросов.
Оптимизация больших списков
Если таблица значений содержит десятки тысяч строк, оператор В может работать медленнее, чем соединение. В таких случаях рассмотрите возможность записи данных во временную таблицу с индексом.
Соединение таблицы значений с основными таблицами
Помимо фильтрации, таблица значений может выступать в роли полноценной виртуальной таблицы в секции ИЗ. Это позволяет выполнять операции соединения (СОЕДИНЕНИЕ, ЛЕВОЕ СОЕДИНЕНИЕ) между реальными данными базы и временным набором. Такой подход особенно полезен, когда нужно не просто отфильтровать данные, а дополнить их информацией из параметра или выполнить агрегацию по группам, заданным в таблице значений.
При выполнении соединения необходимо явно указать условие связи в секции ПО. Имена полей в условии соединения должны соответствовать именам колонок, описанным в параметре таблицы значений. Например, если вы хотите получить остатки только по тем товарам, которые есть в вашем списке, и при этом подтянуть плановые количества из этого же списка, вы напишете:
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток,
План.КоличествоПлан
ИЗ
РегистрНакопления.Остатки КАК Остатки
ЛЕВОЕ СОЕДИНЕНИЕ &ТЗ_План КАК План
ПО Остатки.Номенклатура = План.Номенклатура
Использование ЛЕВОГО СОЕДИНЕНИЯ гарантирует, что все записи из основной таблицы (или из таблицы значений, в зависимости от того, какая стоит слева) будут сохранены в результате, даже если для них нет записей в соединяемой таблице. Это критически важно при построении отчетов, где нужно показать нулевые значения для позиций, по которым не было движения.
Стоит учитывать, что при соединении с таблицей значений сервер 1С создает временную структуру в памяти. Если таблица значений очень велика, это может потребовать значительных ресурсов. Однако для большинства типовых задач (списки до нескольких тысяч элементов) этот метод является наиболее эффективным и чистым с точки зрения архитектуры приложения.
⚠️ Внимание: При использовании соединения убедитесь, что типы данных соединяемых полей полностью совместимы. Неявное преобразование типов в условиях соединения может привести к отказу от использования индексов и существенному замедлению работы запроса.
Обработка пустых таблиц значений и исключения
Один из коварных моментов работы с таблицами значений — поведение запроса при передаче пустой таблицы. Логика оператора В такова: если таблица параметров пуста, то условие Поле В (&ПустаяТаблица) всегда ложно. В результате запрос вернет пустой набор данных, даже если в основной таблице есть подходящие записи. Это поведение часто неочевидно для разработчиков и может привести к тому, что отчеты будут показывать"пустоту" при отсутствии фильтров, если логика формирования параметра не учла этот случай.
Чтобы избежать этой ситуации, необходимо добавлять проверку на заполненность таблицы значений перед выполнением запроса. Если таблица пуста, а логика бизнеса подразумевает получение всех данных (отсутствие фильтра), следует либо не устанавливать параметр (если синтаксис запроса позволяет), либо модифицировать текст запроса, исключая условие фильтрации. Альтернативный вариант — использовать конструкцию ЕСТЬ(ВЫБРАТЬ 1 ИЗ &ТЗ) в условии, но это усложняет запрос.
Также стоит помнить об ограничениях платформы. Хотя таблица значений хранится в оперативной памяти, передача чрезвычайно больших объемов данных (сотни тысяч строк) в параметр запроса может привести к увеличению потребления памяти сервером. В таких сценариях рекомендуется разбивать обработку на пакеты или использовать механизм временных таблиц с последующей индексацией, что дает более предсказуемый результат при работе с Big Data внутри 1С.
- ✅ Всегда проверяйте свойство
ТаблицаЗначений.Количествоперед передачей в запрос. - 🛡️ Обрабатывайте ситуацию пустого фильтра явным образом: либо выбирайте все данные, либо выводите сообщение пользователю.
- ⚙️ При отладке используйте панель отладки запросов, чтобы увидеть фактический текст запроса с подставленными параметрами.
Если в процессе выполнения возникает ошибка, связанная с несоответствием структуры, система выдаст сообщение с указанием номера строки в описании параметров. Внимательно сверяйте порядок и типы полей в коде создания таблицы и в тексте запроса. Часто ошибка кроется в опечатке имени колонки или в том, что тип Строка указан без длины, а в таблицу передается значение большей длины, хотя для запросов 1С длина строки в описании типа часто игнорируется в пользу фактической длины значения.
Пустая ТаблицаЗначений в операторе В всегда дает пустой результат выборки. Это нужно обрабатывать в коде отдельно, чтобы не ломать логику отчетов.
Особенности версий платформы и совместимость
Функционал работы с таблицами значений в запросах развивался вместе с платформой 1С:Предприятие 8. В ранних версиях возможности были ограничены, и разработчики чаще прибегали к созданию временных таблиц через объект ВременнаяТаблица. Начиная с определенных релизов платформы (примерно с версии 8.3.10 и выше), поддержка таблиц значений в параметрах запроса стала стандартной и оптимизированной функцией. Тем не менее, при поддержке старых конфигураций на релизах 8.2 или ранних 8.3 стоит проводить тестирование.
В современных версиях платформы (8.3.20+) добавлены улучшения в оптимизатор запросов, которые лучше распознают паттерны использования таблиц значений и строят более эффективные планы выполнения. Если вы сталкиваетесь с проблемами производительности на старом сервере, попробуйте обновить платформу, прежде чем переписывать логику на временные таблицы. Также стоит учитывать, что в режиме совместимости ниже определенной версии некоторые новые синтаксические конструкции могут быть недоступны.
При разработке новых решений всегда ориентируйтесь на актуальную документацию фирмы"1С". Синтаксические конструкции и поведение оптимизатора могут корректироваться в новых релизах. Если ваш код должен работать в облачных сервисах (1С:Лекторум, 1С:Фреш), убедитесь, что используемые конструкции поддерживаются текущей версией платформы в арендованном окружении, так там обновления происходят автоматически и могут опережать локальные установки.
⚠️ Внимание: Поведение запросов с таблицами значений может отличаться в файловом и клиент-серверном варианте работы из-за различий в управлении памятью и передаче данных между клиентом и сервером. Всегда тестируйте нагрузку на клиент-серверной базе.
Секрет высокой производительности
При передаче таблицы значений на сервер в толстом клиенте данные сериализуются. В тонком клиенте этот процесс оптимизирован. Старайтесь формировать тяжелые таблицы значений на стороне сервера в общих модулях, если это возможно.
Часто задаваемые вопросы (FAQ)
Можно ли передать в запрос таблицу значений без явного описания типов в секции ПАРАМЕТРЫ?
Нет, в языке запросов 1С обязательное требование — полное описание структуры таблицы значений в секции ПАРАМЕТРЫ. Система должна знать типы данных до начала выполнения запроса для построения плана. Исключение составляют некоторые специфические случаи использования конструктора запросов в динамических отчетах, но в стандартном коде описание обязательно.
Что произойдет, если в таблицу значений добавить строку с типом данных, отличным от описанного?
При попытке записать несовместимое значение в колонку таблицы значений (например, строку в числовую колонку) возникнет ошибка выполнения кода 1С еще до момента передачи параметра в запрос. Если же типы совместимы (например, Целое в Число), произойдет автоматическое преобразование, но лучше избегать этого для сохранения производительности.
Как передать таблицу значений из формы в серверный модуль для использования в запросе?
Объект ТаблицаЗначений является сериализуемым. Вы можете передать его как параметр серверной процедуры напрямую из клиентского кода. Однако, если таблица очень большая, это увеличит трафик. Оптимально формировать её сразу на сервере, передавая туда только необходимые примитивные параметры (массивы ID, даты и т.д.).
Есть ли ограничение на количество строк в ТаблицеЗначений для запроса?
Жесткого программного ограничения на количество строк нет, оно ограничено только доступной оперативной памятью сервера 1С и процессора. Однако на практике при превышении 10-50 тысяч строк эффективность оператора В может снижаться, и целесообразнее использовать временные таблицы с индексами.
Можно ли использовать ТаблицуЗначений для вставки данных (INSERT) через запрос?
Нет, язык запросов 1С предназначен только для чтения данных (SELECT). Для вставки, обновления или удаления данных необходимо использовать объект ЗаписьДвижения для регистров или программный код с объектами базы данных. Запрос с таблицей значений может лишь подготовить данные для последующей обработки в цикле.