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

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

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

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

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

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

Частая проблема начинающих разработчиков — запрос «теряет» записи или, наоборот, возвращает лишние строки после добавления условия к временной таблице. Причины почти всегда одни и те же: NULL-значения в полях отбора, отсутствие индексации, неверный порядок пакетов запросов или фильтрация после соединения вместо фильтрации до него.

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

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

Если временная таблица создаётся программно через объект МенеджерВременныхТаблиц, она доступна всем запросам, у которых установлен тот же менеджер. Это позволяет наполнить таблицу один раз и использовать её в нескольких независимых запросах, накладывая разные условия ГДЕ под разные задачи.

Временные таблицы физически размещаются на сервере СУБД (или в памяти для файловой базы) и уничтожаются либо явно командой УНИЧТОЖИТЬ, либо при закрытии менеджера временных таблиц. Пока таблица существует, к ней применимы все стандартные операторы языка запросов: ГДЕ, СОЕДИНЕНИЕ, СГРУППИРОВАТЬ ПО, УПОРЯДОЧИТЬ ПО.

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

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

ВЫБРАТЬ

РеализацияТоваровУслуг.Ссылка КАК Документ,

РеализацияТоваровУслуг.Склад КАК Склад,

РеализацияТоваровУслуг.СуммаДокумента КАК Сумма

ПОМЕСТИТЬ ВТ_Документы

ИЗ

Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

ГДЕ

РеализацияТоваровУслуг.Проведен

И РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода

;

ВЫБРАТЬ

ВТ_Документы.Документ,

ВТ_Документы.Сумма

ИЗ

ВТ_Документы КАК ВТ_Документы

ГДЕ

ВТ_Документы.Склад = &Склад

Обратите внимание: условие во втором запросе работает с полями временной таблицы, а не с полями исходного документа. Если поле не было выбрано на этапе ПОМЕСТИТЬ, использовать его в ГДЕ второго запроса нельзя — конструктор выдаст ошибку «Поле не найдено».

В условии допустимы все стандартные операции: сравнение, В и В ИЕРАРХИИ, ПОДОБНО, проверка ЕСТЬ NULL, логические связки И/ИЛИ/НЕ, а также обращение к параметрам запроса через &.

Где фильтровать: при наполнении или при чтении

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

Фильтрация при чтении оправдана, когда одна и та же временная таблица используется несколько раз с разными отборами. Например, общий набор товаров помещается в ВТ_Товары, а затем один запрос считает остатки по складу А, другой — по складу Б. Дублировать наполнение в этом случае дороже, чем дважды применить ГДЕ.

Где размещать условие

ГДЕ при ПОМЕСТИТЬ

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

ГДЕ при чтении из ВТ

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

Параметры виртуальных таблиц

Для регистров эффективнее всего отбор в параметрах виртуальной таблицы (Период, Условие) ещё до ПОМЕСТИТЬ — так СУБД читает минимум записей.

Индексация полей, участвующих в условии ГДЕ

Временная таблица по умолчанию не имеет индексов, и отбор по ней выполняется полным перебором. Если таблица содержит тысячи строк и по ней идёт фильтрация или соединение, стоит добавить конструкцию ИНДЕКСИРОВАТЬ ПО сразу после секции ГДЕ запроса, создающего таблицу.

ВЫБРАТЬ

Остатки.Номенклатура КАК Номенклатура,

Остатки.КоличествоОстаток КАК Остаток

ПОМЕСТИТЬ ВТ_Остатки

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата, ) КАК Остатки

ИНДЕКСИРОВАТЬ ПО

Номенклатура

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

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

Типичные ошибки при отборе из временной таблицы

Самая коварная проблема — значения NULL. Если поле временной таблицы заполнено не всегда (например, после левого соединения при её формировании), условие ГДЕ Поле = &Значение молча отбрасывает строки с NULL, а ГДЕ Поле <> &Значение тоже их не вернёт: любое сравнение с NULL даёт неопределённый результат. Для таких случаев используйте ЕСТЬ NULL или функцию ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) в условии.

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

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

Типичные ошибки
01
Сравнение поля, содержащего NULL — строки теряются без предупреждения; используйте ЕСТЬNULL или ЕСТЬ NULL.
02
Условие по полю, которое не выбрано на этапе ПОМЕСТИТЬ — ошибка «Поле не найдено»; добавьте поле в выборку временной таблицы.
03
Фильтрация после соединения вместо фильтрации до него — перемножение строк и лишняя нагрузка; накладывайте ГДЕ на каждую таблицу до соединения.
04
Отсутствие ИНДЕКСИРОВАТЬ ПО для больших таблиц — полный перебор при каждом отборе и соединении.
05
Обращение к таблице после УНИЧТОЖИТЬ или в другом менеджере временных таблиц — ошибка «Таблица не найдена».

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

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

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

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

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

Количество строк после ГДЕ
Норма

Меньше или равно числу строк во временной таблице и соответствует ожидаемому отбору

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

Ноль строк при заведомо существующих данных — проверяйте NULL, типы и значения параметров

Поля в условии
Норма

Все поля из ГДЕ присутствуют в выборке ПОМЕСТИТЬ

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

Ошибка «Поле не найдено» при выполнении

Скорость выполнения
Норма

Запрос с индексированной ВТ выполняется заметно быстрее на больших объёмах

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

Время растёт пропорционально размеру ВТ — вероятно, нет индекса по полю отбора

Альтернативы: когда временная таблица не нужна

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

Для отборов по спискам значений удобен приём с таблицей значений в параметре: таблица значений помещается во временную таблицу через ВЫБРАТЬ ... ИЗ &ТЗ (с предварительным Запрос.УстановитьПараметр), а дальше к ней применяются обычные соединения и условия ГДЕ. Это стандартный способ передать произвольный список номенклатуры или контрагентов внутрь запроса.

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

Как выбрать подход

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

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

Можно ли использовать ГДЕ в том же запросе, где ПОМЕСТИТЬ?

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

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

Чаще всего причины три: в поле отбора есть NULL-значения, тип параметра не совпадает с типом поля, либо значения содержат непечатаемые символы или лишние пробелы. Выведите поле отбора в выборку без условия и проверьте фактические значения.

Нужно ли индексировать временную таблицу всегда?

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

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

Используйте в условии оператор В ИЕРАРХИИ: ГДЕ ВТ.Номенклатура В ИЕРАРХИИ(&Группа). Учтите, что такая проверка выполняется обращением к основной таблице справочника и на больших данных может быть медленной — в этом случае выгоднее заранее вычислить состав группы в отдельную временную таблицу.

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

Нет, временные таблицы в языке запросов 1С доступны только для чтения. Чтобы «изменить» данные, создайте новую временную таблицу на основе существующей с нужными вычислениями и отборами, а старую при необходимости уничтожьте.

Чем отличается ГДЕ от ИМЕЮЩИЕ при работе с временной таблицей?

ГДЕ фильтрует строки до группировки, а ИМЕЮЩИЕ — уже сгруппированные результаты по агрегатным функциям (например, ИМЕЮЩИЕ СУММА(Количество) > 0). Если условие можно выразить через обычные поля, используйте ГДЕ — оно выполняется раньше и эффективнее.

Итог

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

Условие ГДЕ к временной таблице работает так же, как к обычной, но эффективнее фильтровать данные уже при ПОМЕСТИТЬ. Следите за NULL-значениями, порядком пакетов запросов и индексируйте поля отборов и соединений в больших временных таблицах.