Разработка и Конфигурация · 11 мин
Условие ГДЕ во временной таблице в запросах 1С
Как использовать конструкцию ГДЕ при работе с временными таблицами в запросах 1С: синтаксис, примеры, индексация, типичные ошибки и проверка результата.
Временные таблицы в языке запросов 1С — это промежуточные наборы данных, которые создаются конструкцией ПОМЕСТИТЬ В и живут в пределах одного пакета запросов или менеджера временных таблиц. Отбор записей из такой таблицы выполняется стандартным оператором ГДЕ, и именно корректное его применение определяет как правильность результата, так и производительность запроса.
Главная особенность в том, что условие ГДЕ можно задавать на двух уровнях: в момент наполнения временной таблицы (отбирать только нужные записи из исходных данных) и при последующем чтении из неё (отбирать из уже подготовленного набора). Выбор уровня влияет на объём обрабатываемых данных и скорость выполнения.
Частая проблема начинающих разработчиков — запрос «теряет» записи или, наоборот, возвращает лишние строки после добавления условия к временной таблице. Причины почти всегда одни и те же: NULL-значения в полях отбора, отсутствие индексации, неверный порядок пакетов запросов или фильтрация после соединения вместо фильтрации до него.
Как устроена работа с временными таблицами в пакетном запросе
Временная таблица создаётся первым запросом пакета с конструкцией ПОМЕСТИТЬ В ИмяТаблицы, а последующие запросы обращаются к ней по имени, как к обычной таблице. Пакеты разделяются точкой с запятой, и порядок строго важен: нельзя обратиться к таблице, которая будет создана ниже по тексту.
Если временная таблица создаётся программно через объект МенеджерВременныхТаблиц, она доступна всем запросам, у которых установлен тот же менеджер. Это позволяет наполнить таблицу один раз и использовать её в нескольких независимых запросах, накладывая разные условия ГДЕ под разные задачи.
Временные таблицы физически размещаются на сервере СУБД (или в памяти для файловой базы) и уничтожаются либо явно командой УНИЧТОЖИТЬ, либо при закрытии менеджера временных таблиц. Пока таблица существует, к ней применимы все стандартные операторы языка запросов: ГДЕ, СОЕДИНЕНИЕ, СГРУППИРОВАТЬ ПО, УПОРЯДОЧИТЬ ПО.
Синтаксис ГДЕ при чтении из временной таблицы
Базовый пример: сначала отбираем проведённые документы во временную таблицу, затем из неё выбираем только нужный склад.
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка КАК Документ,
РеализацияТоваровУслуг.Склад КАК Склад,
РеализацияТоваровУслуг.СуммаДокумента КАК Сумма
ПОМЕСТИТЬ ВТ_Документы
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
РеализацияТоваровУслуг.Проведен
И РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода
;
ВЫБРАТЬ
ВТ_Документы.Документ,
ВТ_Документы.Сумма
ИЗ
ВТ_Документы КАК ВТ_Документы
ГДЕ
ВТ_Документы.Склад = &Склад
Обратите внимание: условие во втором запросе работает с полями временной таблицы, а не с полями исходного документа. Если поле не было выбрано на этапе ПОМЕСТИТЬ, использовать его в ГДЕ второго запроса нельзя — конструктор выдаст ошибку «Поле не найдено».
В условии допустимы все стандартные операции: сравнение, В и В ИЕРАРХИИ, ПОДОБНО, проверка ЕСТЬ NULL, логические связки И/ИЛИ/НЕ, а также обращение к параметрам запроса через &.
Где фильтровать: при наполнении или при чтении
Принципиальное правило: чем раньше отсечены лишние данные, тем меньше объём временной таблицы и тем быстрее работают все последующие запросы пакета. Поэтому условия, которые можно применить к исходным таблицам, следует размещать именно в запросе с ПОМЕСТИТЬ.
Фильтрация при чтении оправдана, когда одна и та же временная таблица используется несколько раз с разными отборами. Например, общий набор товаров помещается в ВТ_Товары, а затем один запрос считает остатки по складу А, другой — по складу Б. Дублировать наполнение в этом случае дороже, чем дважды применить ГДЕ.
Где размещать условие
Подходит, когда отбор един для всех последующих запросов. Минимальный объём временной таблицы, максимальная скорость.
Подходит, когда одна временная таблица используется с разными отборами. Плата — больший размер промежуточных данных.
Для регистров эффективнее всего отбор в параметрах виртуальной таблицы (Период, Условие) ещё до ПОМЕСТИТЬ — так СУБД читает минимум записей.
Индексация полей, участвующих в условии ГДЕ
Временная таблица по умолчанию не имеет индексов, и отбор по ней выполняется полным перебором. Если таблица содержит тысячи строк и по ней идёт фильтрация или соединение, стоит добавить конструкцию ИНДЕКСИРОВАТЬ ПО сразу после секции ГДЕ запроса, создающего таблицу.
ВЫБРАТЬ
Остатки.Номенклатура КАК Номенклатура,
Остатки.КоличествоОстаток КАК Остаток
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата, ) КАК Остатки
ИНДЕКСИРОВАТЬ ПО
Номенклатура
Индексировать нужно те поля, которые участвуют в условиях ГДЕ последующих запросов и в условиях соединений. Индексация всех полей подряд не ускоряет, а замедляет работу: на построение индекса тратятся ресурсы при создании таблицы.
Индексация оправдана, когда временная таблица содержит заметный объём строк и читается с отбором более одного раза. Для таблиц из нескольких десятков записей индекс не даст выигрыша и только усложнит текст запроса.
Типичные ошибки при отборе из временной таблицы
Самая коварная проблема — значения NULL. Если поле временной таблицы заполнено не всегда (например, после левого соединения при её формировании), условие ГДЕ Поле = &Значение молча отбрасывает строки с NULL, а ГДЕ Поле <> &Значение тоже их не вернёт: любое сравнение с NULL даёт неопределённый результат. Для таких случаев используйте ЕСТЬ NULL или функцию ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) в условии.
Вторая частая ошибка — обращение к временной таблице до её создания или после уничтожения. Движок запросов выполняет пакеты строго сверху вниз, и нарушение порядка приводит к ошибке «Таблица не найдена». То же произойдёт, если запрос выполняется без того менеджера временных таблиц, в котором таблица была создана.
Третья группа ошибок связана с типами данных. Если параметр &Склад имеет составной тип или передано значение другого типа, чем поле, сравнение может не сработать без явного сообщения об ошибке. Проверяйте типы через ВЫРАЗИТЬ или гарантируйте корректный тип параметра на стороне кода.
Проверка результата и отладка запроса
Отлаживать пакетный запрос удобнее всего по частям. Выполните сначала только первый пакет с ПОМЕСТИТЬ, заменив его на обычную выборку (убрав ПОМЕСТИТЬ), и убедитесь, что исходный набор данных корректен. Затем добавьте второй пакет с условием ГДЕ и сравните количество строк до и после фильтрации.
Для программной проверки используйте Результат.Выгрузить() и анализируйте таблицу значений: количество строк, наличие NULL в ключевых полях, типы колонок. Если условие «не срабатывает», временно выведите само поле отбора в выборку — часто оказывается, что значения содержат лишние пробелы, другой регистр или неожиданный тип.
Как проверить результат
Меньше или равно числу строк во временной таблице и соответствует ожидаемому отбору
Ноль строк при заведомо существующих данных — проверяйте NULL, типы и значения параметров
Все поля из ГДЕ присутствуют в выборке ПОМЕСТИТЬ
Ошибка «Поле не найдено» при выполнении
Запрос с индексированной ВТ выполняется заметно быстрее на больших объёмах
Время растёт пропорционально размеру ВТ — вероятно, нет индекса по полю отбора
Альтернативы: когда временная таблица не нужна
Не каждый отбор требует временной таблицы. Если данные нужны один раз и логика простая, вложенный запрос в секции ИЗ или условие В (ВЫБРАТЬ ...) решают задачу компактнее. Временная таблица оправдана при многократном использовании одного набора, сложной многошаговой подготовке данных или необходимости индексации.
Для отборов по спискам значений удобен приём с таблицей значений в параметре: таблица значений помещается во временную таблицу через ВЫБРАТЬ ... ИЗ &ТЗ (с предварительным Запрос.УстановитьПараметр), а дальше к ней применяются обычные соединения и условия ГДЕ. Это стандартный способ передать произвольный список номенклатуры или контрагентов внутрь запроса.
Как выбрать подход
Частые вопросы
Можно ли использовать ГДЕ в том же запросе, где ПОМЕСТИТЬ?
Да, и это нужно делать в первую очередь: условие в запросе с ПОМЕСТИТЬ ограничивает данные ещё до попадания во временную таблицу, что уменьшает её размер и ускоряет все последующие обращения к ней.
Почему условие ГДЕ по временной таблице возвращает пустой результат?
Чаще всего причины три: в поле отбора есть NULL-значения, тип параметра не совпадает с типом поля, либо значения содержат непечатаемые символы или лишние пробелы. Выведите поле отбора в выборку без условия и проверьте фактические значения.
Нужно ли индексировать временную таблицу всегда?
Нет. Индексация оправдана для таблиц с заметным количеством строк, по которым выполняются соединения или повторные отборы. Для маленьких таблиц построение индекса может занять больше времени, чем сам перебор.
Как отфильтровать временную таблицу по иерархии справочника?
Используйте в условии оператор В ИЕРАРХИИ: ГДЕ ВТ.Номенклатура В ИЕРАРХИИ(&Группа). Учтите, что такая проверка выполняется обращением к основной таблице справочника и на больших данных может быть медленной — в этом случае выгоднее заранее вычислить состав группы в отдельную временную таблицу.
Можно ли изменить данные во временной таблице после создания?
Нет, временные таблицы в языке запросов 1С доступны только для чтения. Чтобы «изменить» данные, создайте новую временную таблицу на основе существующей с нужными вычислениями и отборами, а старую при необходимости уничтожьте.
Чем отличается ГДЕ от ИМЕЮЩИЕ при работе с временной таблицей?
ГДЕ фильтрует строки до группировки, а ИМЕЮЩИЕ — уже сгруппированные результаты по агрегатным функциям (например, ИМЕЮЩИЕ СУММА(Количество) > 0). Если условие можно выразить через обычные поля, используйте ГДЕ — оно выполняется раньше и эффективнее.
Что важно запомнить
Условие ГДЕ к временной таблице работает так же, как к обычной, но эффективнее фильтровать данные уже при ПОМЕСТИТЬ. Следите за NULL-значениями, порядком пакетов запросов и индексируйте поля отборов и соединений в больших временных таблицах.