К статье
Практический материал

Разработка и Конфигурация · 13 мин

Таблица как параметр в 1С: способы передачи и практические примеры

Как передать таблицу значений как параметр в 1С: в процедуры и функции, между клиентом и сервером, в запросы. Примеры кода, ограничения и типичные ошибки.

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

У передачи таблицы есть особенности, которые регулярно становятся источником ошибок: таблица значений передаётся по ссылке внутри одного контекста, но копируется при переходе между клиентом и сервером; не всякий серверный вызов допускает такой параметр; запрос принимает таблицу только через временную таблицу. Понимание этих правил позволяет выбрать правильный способ передачи и избежать лишних вызовов сервера и потерь производительности.

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

Как передать таблицу значений в процедуру или функцию

Таблица значений — обычный объект встроенного языка, поэтому она передаётся в процедуру или функцию так же, как любой другой параметр. Достаточно объявить параметр в заголовке метода и передать переменную с таблицей при вызове:

Процедура ОбработатьТаблицу(ТаблицаДанных) Экспорт

Для Каждого Строка Из ТаблицаДанных Цикл

Строка.СуммаСНДС = Строка.Сумма * 1.2;

КонецЦикла;

КонецПроцедуры

// Вызов

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

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

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

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

ОбработатьТаблицу(ТЗ);

Важный момент: по умолчанию параметр передаётся по ссылке. Это значит, что все изменения, которые процедура внесёт в таблицу (добавление строк, изменение значений, очистка), будут видны в вызывающем коде. В примере выше после вызова ОбработатьТаблицу колонка «СуммаСНДС» в исходной таблице ТЗ уже заполнена — отдельно возвращать таблицу не нужно.

Если таблицу нужно вернуть из функции, используют либо возврат через Возврат, либо тот же приём с изменением параметра по ссылке. Оба подхода рабочие, но возврат через Возврат делает код понятнее, когда функция создаёт таблицу «с нуля», а изменение параметра удобно, когда таблица уже существует и её нужно только дополнить.

Передача по значению и по ссылке: в чём разница

Ключевое слово Знач перед именем параметра меняет способ передачи: в процедуру попадает копия таблицы, и любые изменения внутри не затрагивают исходную таблицу вызывающего кода. Это защищает данные от случайной порчи, но требует создания полной копии таблицы в памяти.

// Изменения НЕ затронут исходную таблицу

Процедура РассчитатьКопию(Знач ТаблицаДанных)

ТаблицаДанных.Очистить(); // исходная таблица останется нетронутой

КонецПроцедуры

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

Маршрут решения

Как выбрать способ передачи

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

Передача таблицы в запрос через временную таблицу

Запрос в 1С не умеет напрямую «пробежаться» по таблице значений, но умеет принимать её как параметр и помещать во временную таблицу. Для этого в тексте запроса используется конструкция ПОМЕСТИТЬ, а таблица передаётся через УстановитьПараметр:

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

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

"ВЫБРАТЬ

| ВТ.Номенклатура,

| ВТ.Количество

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

|ИЗ

| &ТаблицаТоваров КАК ВТ

|;

|ВЫБРАТЬ

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

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

| Спр.Наименование

|ИЗ

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

| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Спр

| ПО ВТ_Данные.Номенклатура = Спр.Ссылка";

Запрос.УстановитьПараметр("ТаблицаТоваров", ТЗ);

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

Имена колонок таблицы значений должны совпадать с именами полей, указанными в секции ВЫБРАТЬ первого запроса пакета. Если колонка в таблице называется иначе, запрос завершится ошибкой. Также следите за типами колонок: неявное приведение типов при помещении во временную таблицу может дать неожиданный результат, особенно для составных типов.

Такой приём незаменим, когда нужно соединить данные, собранные программно (например, загруженные из Excel), с данными информационной базы: остатками, ценами, ссылками справочников. Альтернатива — обход таблицы в цикле с отдельными запросами на каждую строку — работает на порядки медленнее и считается грубой ошибкой.

Передача таблицы между клиентом и сервером

В управляемых формах код делится на клиентский и серверный. Таблица значений может передаваться в серверные процедуры и функции, но с ограничениями: вызов должен быть объявлен с директивой &НаСервере (без контекста формы такая передача проще всего), а сама таблица при вызове сериализуется — то есть преобразуется в передаваемое представление и копируется на сервер.

&НаКлиенте

Процедура ЗагрузитьДанные(Команда)

ТЗ = СформироватьТаблицуНаКлиенте();

ЗаписатьДанныеНаСервере(ТЗ);

КонецПроцедуры

&НаСервереБезКонтекста

Процедура ЗаписатьДанныеНаСервере(ТаблицаДанных)

Для Каждого Строка Из ТаблицаДанных Цикл

// запись в регистр или справочник

КонецЦикла;

КонецПроцедуры

Изменения, внесённые серверной процедурой в таблицу-параметр, возвращаются на клиент после завершения вызова — платформа сериализует параметры обратно. Однако каждый такой вызов — это передача всей таблицы по сети дважды (туда и обратно). Для больших таблиц это заметная нагрузка, поэтому на клиенте стоит собирать только необходимый минимум колонок и строк.

Частный случай — таблица, привязанная к реквизиту формы (тип «ТаблицаЗначений» или «ДанныеФормыКоллекция»). Такую таблицу нельзя напрямую передать в серверную процедуру без контекста: сначала её преобразуют в таблицу значений. В типовых механизмах для этого используется метод формы, возвращающий таблицу значений из реквизита формы, либо обработку выполняют в контекстной серверной процедуре &НаСервере.

Типичные ошибки
01
Передача таблицы в &НаСервереБезКонтекста из реквизита формы напрямую — ошибка преобразования данных; сначала получите таблицу значений
02
Ожидание, что «Знач» ускорит серверный вызов — при клиент-серверном вызове таблица копируется в любом случае
03
Цикл с запросом внутри вместо передачи таблицы в запрос — резкое падение производительности на больших объёмах
04
Изменение таблицы, переданной по ссылке, без предупреждения в комментарии — вызывающий код получает неожиданно изменённые данные
05
Несовпадение имён колонок таблицы и полей в тексте запроса — ошибка выполнения пакетного запроса

Табличная часть и таблица значений: что передавать

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

ТЗТовары = Объект.Товары.Выгрузить();

ПроверитьЗаполнениеТоваров(ТЗТовары);

Такой подход отвязывает процедуру от конкретного документа: одна и та же проверка сможет работать и с табличной частью реализации, и с таблицей, загруженной из файла. Метод Выгрузить() без параметров копирует все колонки; если нужны только некоторые, передайте их имена строкой через запятую — это уменьшит объём копируемых данных.

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

Порядок действий: передать таблицу в запрос
  1. 1
    Сформируйте таблицу значений и явно опишите колонки с типами через ОписаниеТипов
  2. 2
    В тексте запроса добавьте первый пакет: ВЫБРАТЬ поля ПОМЕСТИТЬ ВТ ИЗ &ИмяПараметра
  3. 3
    Установите параметр: Запрос.УстановитьПараметр("ИмяПараметра", ТЗ)
  4. 4
    Во втором пакете соедините временную таблицу с данными ИБ
  5. 5
    Выполните запрос и проверьте количество строк результата — оно должно соответствовать ожиданиям по исходной таблице

Производительность и проверка результата

Таблица значений — объект в памяти, и её копирование (при передаче по значению, при сериализации на сервер, при Скопировать()) стоит ресурсов пропорционально числу строк и колонок. Для таблиц в десятки тысяч строк лишние копирования становятся заметными. Практические меры: передавать по ссылке там, где это безопасно; выгружать только нужные колонки; не передавать таблицу на сервер несколько раз подряд — лучше один серверный вызов, выполняющий всю обработку.

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

Контрольные точки

Как проверить результат

Количество строк после вызова процедуры
Норма

Совпадает с ожидаемым (или изменилось предсказуемо)

Тревожный признак

Строки пропали или задвоились без явной причины — проверьте логику внутри процедуры

Изменения в исходной таблице
Норма

Видны при передаче по ссылке, отсутствуют при передаче с «Знач»

Тревожный признак

Таблица изменилась, хотя передавалась с «Знач» — где-то передаётся не та переменная

Результат запроса с временной таблицей
Норма

Число строк результата согласуется с числом строк исходной таблицы

Тревожный признак

Пустой результат — проверьте имена колонок и типы данных

Серверный вызов с таблицей
Норма

Выполняется без ошибок преобразования

Тревожный признак

Ошибка сериализации — в таблице есть неподдерживаемый тип значения

Частые вопросы о передаче таблицы как параметра

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

Да, таблица значений допустима как параметр фонового задания, но она будет сериализована при постановке задания. Для больших таблиц это создаёт заметную нагрузку на хранилище параметров задания; часто эффективнее передать в фоновое задание ключи или настройки, а данные получить на сервере заново.

Чем отличается передача таблицы в функцию от передачи в процедуру?

Технически — ничем: правила передачи по ссылке и по значению одинаковы. Разница только в стиле: функция обычно возвращает результат через «Возврат», поэтому если таблица создаётся внутри, её возвращают как значение функции, а изменение входного параметра считается менее прозрачным стилем.

Почему запрос с параметром-таблицей выдаёт ошибку «Поле не найдено»?

Имя поля в секции ВЫБРАТЬ первого пакета не совпадает с именем колонки таблицы значений. Сравните имена посимвольно, включая регистр букв и возможные пробелы. Также проверьте, что колонка вообще добавлена в таблицу до передачи в запрос.

Можно ли передать таблицу значений через хранилище значения?

Да, таблицу можно упаковать в ХранилищеЗначения и сохранить в базу, а затем извлечь и передать дальше. Это используют для кэширования или передачи данных между сеансами. Учтите, что при извлечении создаётся новая таблица — связи с исходной уже нет.

Что быстрее: передать таблицу в запрос или обойти её циклом с поиском?

Передача в запрос практически всегда быстрее, если внутри цикла выполняются обращения к базе данных. Один запрос с временной таблицей заменяет тысячи отдельных запросов. Цикл оправдан, только если обработка чисто вычислительная и не обращается к данным ИБ.

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

Используйте метод «Скопировать» с отбором: сначала постройте структуру отбора, затем вызовите ТЗ.Скопировать(Отбор) и передайте полученную таблицу. Альтернатива — передать всю таблицу вместе со структурой отбора и применить «НайтиСтроки» уже внутри процедуры, что избавляет от лишнего копирования.

Итог

Что важно запомнить

Таблица значений передаётся как обычный параметр: по ссылке — для изменения, с «Знач» — для защиты исходных данных. В запрос таблица попадает через ПОМЕСТИТЬ и УстановитьПараметр, между клиентом и сервером — через сериализацию с неизбежным копированием. Для больших таблиц минимизируйте копии и серверные вызовы, а корректность передачи проверяйте по количеству строк и заполненности ключевых колонок.