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

· 9 мин

Содержание

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

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

Подготовка таблицы значений: колонки и типы

Главный шаг, который пропускают чаще всего, — типизация колонок. Колонка, созданная через ТЗ.Колонки.Добавить("Номенклатура") без описания типов, хранит значения произвольного типа. Такую колонку запрос выбрать не может, и выполнение прерывается ошибкой.

Правильное создание таблицы в коде:

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
ТЗ.Колонки.Добавить("Комментарий", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)));
ТЗ.Колонки.Добавить("ДатаОтгрузки", Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)));

Что учесть при выборе типов:

  • 🔢 Числа — задавайте разрядность и точность. Без квалификатора колонка тоже работает, но при сложении и сравнении с полями базы точность может отличаться от ожидаемой.
  • 🔤 Строки — указывайте длину. Строка неограниченной длины в запросе ведёт себя как поле «Строка (0)»: по ней нельзя группировать и нельзя сравнивать её на равенство без ПОДСТРОКА().
  • 🔗 Ссылки — тип ссылки должен совпадать с тем, с чем вы потом соединяете таблицу. Колонка СправочникСсылка.Номенклатура соединяется с Справочник.Номенклатура.Ссылка без лишних проверок типов.
  • 🧩 Составной тип допустим: Новый ОписаниеТипов("СправочникСсылка.Контрагенты, СправочникСсылка.ФизическиеЛица"). Но каждое значение такого поля при соединении проверяется на несколько таблиц — запрос получается тяжелее.

Если таблица пришла из чужого кода (результат другого запроса, табличная часть, загрузка из Excel ), проверьте типы колонок перед передачей:

Для Каждого Колонка Из ТЗ.Колонки Цикл
	Сообщить(Колонка.Имя + ": " + Строка(Колонка.ТипЗначения));
КонецЦикла;

Пустая строка после двоеточия означает, что у колонки нет описания типов. Такую колонку нужно пересоздать с типом.

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

Передавайте только нужные колонки

Большую таблицу с десятком колонок не стоит гнать в запрос целиком. Скопируйте нужные:

ТЗДляЗапроса = ТЗ.Скопировать(, "Номенклатура, Количество");

Меньше колонок — меньше данных уходит на сервер СУБД и во временную таблицу.

Текст запроса с параметром-таблицей

Параметр-таблица всегда идёт первым пакетом и всегда с ПОМЕСТИТЬ. Сначала вы описываете, какие колонки взять, затем работаете с временной таблицей как с обычной.

ВЫБРАТЬ
	Т.Номенклатура КАК Номенклатура,
	Т.Количество КАК Количество
ПОМЕСТИТЬ ВТ_Товары
ИЗ
	&ТаблицаТоваров КАК Т
ИНДЕКСИРОВАТЬ ПО
	Номенклатура
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВТ.Номенклатура КАК Номенклатура,
	ВТ.Количество КАК Количество,
	ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
	ВТ_Товары КАК ВТ
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(, ) КАК Остатки
		ПО ВТ.Номенклатура = Остатки.Номенклатура

Правила синтаксиса, которые здесь работают:

  1. Перед именем параметра ставится &, после — обязательный псевдоним через КАК.
  2. Поля перечисляются через псевдоним: Т.Номенклатура. Звёздочка ВЫБРАТЬ * из параметра-таблицы тоже допустима, но явный список нагляднее и не тащит лишние колонки.
  3. Имена полей совпадают с именами колонок таблицы значений. Опечатка в имени даёт ошибку разбора текста.
  4. В первом запросе пакета нельзя соединять параметр-таблицу с таблицами базы. Сначала ПОМЕСТИТЬ, соединения — в следующем запросе.

В первом запросе можно отфильтровать и сгруппировать строки:

ВЫБРАТЬ
	Т.Номенклатура КАК Номенклатура,
	СУММА(Т.Количество) КАК Количество
ПОМЕСТИТЬ ВТ_Товары
ИЗ
	&ТаблицаТоваров КАК Т
ГДЕ
	Т.Количество > 0
СГРУППИРОВАТЬ ПО
	Т.Номенклатура

Так дубли строк схлопываются ещё до соединения с регистром.

Передача из кода выглядит стандартно:

Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("ТаблицаТоваров", ТЗДляЗапроса);
Выборка = Запрос.Выполнить().Выбрать();

Как ввести таблицу значений в консоли запросов

Консоль запросов — внешняя обработка КонсольЗапросов.epf (её распространяют с диска ИТС) или аналоги сторонних авторов. Открывается через Файл → Открыть в режиме 1С:Предприятие под пользователем с правом открывать внешние обработки. Интерфейс разных версий консоли отличается, но порядок действий одинаковый.

  1. Вставьте текст запроса в поле текста и нажмите команду заполнения параметров. Консоль разберёт текст и добавит строку ТаблицаТоваров в список параметров.
  2. В строке параметра смените тип значения на «Таблица значений». В большинстве версий тип выбирается в колонке типа или в окне выбора типа, которое открывается из поля значения.
  3. Откройте редактор значения параметра. Появится пустая таблица.
  4. Добавьте колонки. Имена — ровно как в тексте запроса: Номенклатура, Количество. Каждой колонке задайте тип: ссылку на справочник, число, строку с длиной.
  5. Добавьте строки и заполните их. Для ссылочной колонки откроется форма выбора элемента справочника, для числа — поле ввода.
  6. Закройте редактор и выполните запрос.

Колонка без типа — главная причина ошибки в консоли. Если редактор позволяет добавить колонку, не указав тип, консоль передаст в запрос нетипизированную колонку, и запрос не выполнится.

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

Если в консоли нет редактора таблицы

Не во всех версиях консоли есть удобный ввод таблицы. Обходной путь — заменить параметр-таблицу временной таблицей, собранной прямо в тексте:

ВЫБРАТЬ
	&Товар1 КАК Номенклатура,
	5 КАК Количество
ПОМЕСТИТЬ ВТ_Товары

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	&Товар2,
	12

Имена полей задаёт первый запрос объединения, ПОМЕСТИТЬ тоже пишется только в нём. Параметры &Товар1, &Товар2 — обычные ссылки, их консоль вводит без проблем. Для отладки на трёх-пяти строках этого хватает. Когда запрос заработал, первую часть меняете на ИЗ &ТаблицаТоваров и переносите в код.

Обработка с кодом вместо ручного ввода

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

Таблица значений в условии В и в соединениях

Параметр-таблицу используют двумя способами: как источник строк и как фильтр. Для фильтра есть два варианта.

Вариант 1. Подзапрос к временной таблице. Самый надёжный:

ВЫБРАТЬ
	Продажи.Номенклатура,
	Продажи.Количество
ИЗ
	РегистрНакопления.Продажи КАК Продажи
ГДЕ
	Продажи.Номенклатура В
			(ВЫБРАТЬ
				ВТ.Номенклатура
			ИЗ
				ВТ_Товары КАК ВТ)

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

Когда что выбирать:

СпособКогда подходитНа что смотреть
Массив в В (&Список)фильтр по одному полю, до нескольких тысяч значенийна больших объёмах текст запроса к СУБД раздувается
Временная таблица и В (ВЫБРАТЬ ...)фильтр по одному или нескольким полям, любые объёмынужна индексация по полю отбора
Временная таблица и ВНУТРЕННЕЕ СОЕДИНЕНИЕнужны поля из таблицы значений в результатедубли в таблице дают дубли строк результата

Соединение с виртуальной таблицей остатков или оборотов работает быстрее, если отбор задан в её параметрах: Остатки(, Номенклатура В (ВЫБРАТЬ ВТ.Номенклатура ИЗ ВТ_Товары КАК ВТ)). Тогда СУБД считает остатки только по нужным товарам, а не по всем.

Ошибки при передаче таблицы значений и как их исправить

Тексты сообщений немного отличаются в разных версиях платформы, поэтому ниже — по смыслу ошибки.

Диагностика: выберите симптом

Ещё одна ловушка не даёт ошибки, а тихо искажает результат. Если колонка числовая, а в части строк значение не заполнено, в запросе это будет 0, а не NULL. Для ссылочной колонки незаполненное значение — пустая ссылка. Условие ЕСТЬ NULL такие строки не поймает: проверяйте = 0 или = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка).

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

Таблица значений живёт в памяти сервера 1С. При выполнении запроса платформа целиком передаёт её на сервер СУБД и создаёт там временную таблицу. На 50 строках это незаметно, на 200 тысячах — заметно.

Приёмы, которые дают реальную разницу:

  • 📉 Сокращайте таблицу до передачи. Удалите лишние колонки через Скопировать, сверните дубли через ТЗ.Свернуть("Номенклатура", "Количество").
  • 🗂 Индексируйте временную таблицу по полям, по которым соединяете: ИНДЕКСИРОВАТЬ ПО Номенклатура. Для таблицы в десяток строк индекс не нужен — он сам стоит времени.
  • 🔁 Не выполняйте запрос в цикле. Классическая ошибка — по запросу на каждую строку таблицы значений. Один запрос с параметром-таблицей вместо тысячи мелких ускоряет обработку в разы.
  • 🧠 Используйте менеджер временных таблиц, если одна и та же таблица нужна нескольким запросам. Поместите её один раз, а дальше обращайтесь по имени:
МВТ = Новый МенеджерВременныхТаблиц;

Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст =
"ВЫБРАТЬ
|	Т.Номенклатура КАК Номенклатура,
|	Т.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
|	&ТаблицаТоваров КАК Т
|ИНДЕКСИРОВАТЬ ПО
|	Номенклатура";
Запрос.УстановитьПараметр("ТаблицаТоваров", ТЗДляЗапроса);
Запрос.Выполнить();

// Второй запрос использует ВТ_Товары без повторной передачи таблицы
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МВТ;
Запрос2.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК Строк ИЗ ВТ_Товары КАК ВТ";
Выборка = Запрос2.Выполнить().Выбрать();
Выборка.Следующий();
Сообщить("Строк во временной таблице: " + Формат(Выборка.Строк, "ЧГ=0"));

МВТ.Закрыть();

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

На клиенте таблицы значений нет: в управляемой форме её заменяет ДанныеФормыКоллекция. Запрос с параметром-таблицей выполняйте в серверной процедуре, а таблицу получайте там через РеквизитФормыВЗначение().

Когда таблица значений — не лучший выбор

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

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

Можно ли передать в запрос дерево значений?
Нет. Дерево значений запрос не принимает. Выгрузите нужный уровень в таблицу значений с типизированными колонками и передавайте её.
Сколько строк выдержит параметр-таблица?
Жёсткого лимита в несколько тысяч строк нет, ограничение — память сервера 1С и время передачи в СУБД. Сотни тысяч строк передаются, но такой объём лучше сначала свернуть и сократить по колонкам.
Работает ли параметр-таблица в файловой базе?
Да, синтаксис и правила те же: первый запрос с ПОМЕСТИТЬ, типизированные колонки. Временная таблица создаётся средствами файловой СУБД.
Можно ли использовать параметр-таблицу в системе компоновки данных?
Можно, но только при программном формировании отчёта: значение параметра-таблицы устанавливают из кода. Альтернатива — набор данных «Объект», в который таблица значений передаётся как внешний набор данных.
Почему в консоли запрос работает, а в коде нет?
Чаще всего в коде таблица создана без типов колонок, а в консоли вы задали типы вручную. Сравните типы колонок перед вызовом УстановитьПараметр.