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

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

Запрос 1С с условием ГДЕ по таблице значений

Как использовать таблицу значений в запросе 1С: передача через параметр, условие ГДЕ В, соединение с временной таблицей, типичные ошибки и примеры кода.

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

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

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

Почему нельзя написать ГДЕ прямо по таблице значений

Язык запросов 1С работает с таблицами базы данных и временными таблицами, но таблица значений — это объект встроенного языка, живущий в памяти сервера или клиента. У запроса нет прямого доступа к этому объекту: его нужно явно передать через параметр методом Запрос.УстановитьПараметр("ТЗ", ТаблицаЗначений).

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

Способ 1. Условие ГДЕ В со списком значений

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

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

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

"ВЫБРАТЬ

| Товары.Ссылка КАК Номенклатура,

| Товары.Наименование

|ИЗ

| Справочник.Номенклатура КАК Товары

|ГДЕ

| Товары.Ссылка В (&СписокСсылок)";

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

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

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

Метод ВыгрузитьКолонку() возвращает массив значений колонки, а оператор В корректно работает с массивом, переданным как параметр. Дубли в массиве не страшны для отбора, но лучше заранее свернуть таблицу, чтобы не тащить лишние данные в запрос.

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

Способ 2. Помещение таблицы значений во временную таблицу

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

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

Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

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

"ВЫБРАТЬ

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

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

|ПОМЕСТИТЬ ВТ_Подбор

|ИЗ

| &ТЗ КАК ТЗ

|;

|

|ВЫБРАТЬ

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

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

| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

|ИЗ

| ВТ_Подбор КАК ВТ

| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки

| ПО ВТ.Номенклатура = Остатки.Номенклатура";

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

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

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

Сохранение порядка строк и дублей

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

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

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

Строка.НомерСтроки = ТЗ.Индекс(Строка) + 1;

КонецЦикла;

Затем выберите это поле во временную таблицу и добавьте УПОРЯДОЧИТЬ ПО НомерСтроки в итоговый запрос. Дубли при необходимости убираются заранее методом ТЗ.Свернуть("Номенклатура", "Количество") — это заодно уменьшит объём передаваемых в запрос данных.

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

Типичные ошибки и как их диагностировать

Первая группа ошибок — нетипизированные колонки. Если таблица значений получена программно через Новый ТаблицаЗначений и колонки добавлены без описания типов, запрос может отказаться принимать параметр или неверно сравнивать значения. Всегда задавайте тип через Новый ОписаниеТипов(...), а для ссылочных полей — точный тип ссылки, а не составной без необходимости.

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

Типичные ошибки
01
Колонки таблицы значений без описания типов — запрос не принимает параметр или сравнение работает неверно
02
Имя поля в тексте запроса не совпадает с именем колонки таблицы — ошибка «Поле не найдено» при выполнении
03
ЛЕВОЕ соединение без ЕСТЬNULL — в результате NULL вместо нуля ломает итоги и условия
04
Передача таблицы с дублями без свёртки — лишняя нагрузка и размножение строк при соединении
05
Ожидание исходного порядка строк без колонки номера и УПОРЯДОЧИТЬ — строки приходят в произвольном порядке
06
Использование В (&Список) с очень большим массивом — падение производительности вместо временной таблицы

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

После выполнения запроса сверьте количество строк результата с ожиданием. При ВНУТРЕННЕМ соединении строк не может быть больше, чем уникальных совпадений; при ЛЕВОМ от временной таблицы — не меньше, чем строк во временной таблице (если в базе нет дублей по ключу соединения). Резкое разрастание результата — признак того, что ключ соединения не уникален с обеих сторон.

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

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

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

Количество строк результата при ЛЕВОМ соединении
Норма

Не меньше числа строк временной таблицы

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

Строк меньше — часть подбора потеряна, проверьте типы полей соединения

Значения числовых полей из таблицы базы
Норма

Нули и конкретные числа

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

NULL — добавьте ЕСТЬNULL вокруг полей правой таблицы

Порядок строк
Норма

Совпадает с исходной таблицей при наличии УПОРЯДОЧИТЬ ПО номеру строки

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

Произвольный — колонка номера не добавлена или не выбрана

Выполнение без исключений
Норма

Запрос выполняется, выгрузка заполнена

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

Ошибка «Поле не найдено» или типа параметра — сверить имена колонок и описания типов

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

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

Да, если нужен только отбор по одной колонке: выгрузите колонку в массив методом ВыгрузитьКолонку() и используйте условие ГДЕ Поле В (&Массив). Для соединений и переноса нескольких колонок без временной таблицы не обойтись.

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

Чаще всего колонка таблицы значений не имеет явного типа или тип значения в ней не совпадает с типом поля базы. Задайте колонке точное описание типов, например Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), и убедитесь, что в строках нет значений других типов.

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

Создайте объект МенеджерВременныхТаблиц и назначьте его каждому запросу через свойство МенеджерВременныхТаблиц. Первый запрос помещает таблицу через ПОМЕСТИТЬ, последующие читают её по имени. После работы менеджер можно закрыть методом Закрыть().

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

При помещении во временную таблицу без СВЕРНУТЬ дубли сохраняются, но итоговое количество строк зависит от соединения: ВНУТРЕННЕЕ соединение с дублями в ВТ даст повторяющиеся строки результата. Если дубли не нужны, сверните таблицу до передачи в запрос.

Что быстрее: ГДЕ В (&Список) или соединение с временной таблицей?

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

Можно ли отладить содержимое временной таблицы?

Да: добавьте в пакет отдельный запрос ВЫБРАТЬ * ИЗ ВТ_Имя и выполните его с тем же менеджером временных таблиц, либо в конфигураторе при отладке посмотрите результат выборки. Это самый надёжный способ убедиться, что таблица значений передалась в запрос полностью и с правильными типами.

Итог

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

Таблица значений передаётся в запрос только через параметр. Для простого отбора по ссылкам достаточно ГДЕ В (&Массив), для соединений и переноса колонок — помещение во временную таблицу через ПОМЕСТИТЬ. Всегда типизируйте колонки, сворачивайте дубли, используйте ЕСТЬNULL при ЛЕВОМ соединении и колонку с номером строки, если важен порядок.