В процессе написания запросов в 1С можно столкнуться с ситуацией, которая на первый взгляд кажется нелогичной. Например, мы пытаемся получить данные из виртуальной таблицы остатков регистра накопления и накладываем простое условие в секции ГДЕ, но запрос возвращает пустой результат, хотя мы точно знаем, что данные, удовлетворяющие условию, в базе есть. Рассмотрим, почему так происходит и как правильно конструировать такие запросы.
Проанализируем типичную проблему: есть запрос к виртуальной таблице РегистрНакопления.ВзаиморасчетыСКонтрагентамиПоДокументамРасчетов.Остатки. В секции ГДЕ мы устанавливаем отбор по измерению ДоговорКонтрагента, передавая в параметр конкретный договор. В результате запрос ничего не находит. Давайте разберемся, в чем кроется причина и как это исправить.
Ключ к пониманию проблемы лежит в механизме работы виртуальных таблиц в 1С. Когда мы пишем запрос, есть два основных способа отфильтровать данные из виртуальной таблицы:
ГДЕ в основном тексте запроса. Этот способ предназначен для фильтрации уже полученного и агрегированного результата.Давайте посмотрим на пример запроса, который работает некорректно:
ВЫБРАТЬ
ВзаиморасчетыОстатки.Контрагент,
ВзаиморасчетыОстатки.СуммаВзаиморасчетовОстаток
ИЗ
РегистрНакопления.ВзаиморасчетыСКонтрагентамиПоДокументамРасчетов.Остатки КАК ВзаиморасчетыОстатки
ГДЕ
ВзаиморасчетыОстатки.ДоговорКонтрагента = &ДоговорКонтрагента
Почему этот запрос не возвращает данные? Процесс его выполнения выглядит так:
...Остатки без каких-либо условий по измерениям. Она вычисляет остатки по всем договорам, контрагентам и т.д., которые есть в регистре на текущий момент.ДоговорКонтрагента не было указано в списке полей ВЫБРАТЬ и не участвовало в группировках, его может просто не быть в этой результирующей таблице. Виртуальная таблица отбирает только те поля, которые явно запрошены или необходимы для расчета итогов.ГДЕ. Так как в результирующем наборе поля ДоговорКонтрагента, скорее всего, нет, то и фильтровать по нему невозможно. Результат — пустая выборка.Иными словами, ГДЕ — это постфильтрация. Она работает с тем, что уже посчитала и вернула виртуальная таблица. Если нужного поля для фильтрации в этом результате нет, отбор не сработает.
Чтобы запрос работал корректно и, что не менее важно, оптимально, условия по измерениям регистра необходимо передавать непосредственно в параметры виртуальной таблицы. Это сообщает платформе, что данные нужно отфильтровать до того, как будут рассчитываться итоги.
Синтаксис обращения к виртуальной таблице остатков выглядит так: ИмяРегистра.Остатки(Период, Условие).
Посмотрим на правильный вариант того же запроса:
ВЫБРАТЬ
ВзаиморасчетыОстатки.Контрагент,
ВзаиморасчетыОстатки.СуммаВзаиморасчетовОстаток
ИЗ
РегистрНакопления.ВзаиморасчетыСКонтрагентамиПоДокументамРасчетов.Остатки(
,
ДоговорКонтрагента = &ДоговорКонтрагента) КАК ВзаиморасчетыОстатки
В этом случае происходит следующее:
ДоговорКонтрагента = &ДоговорКонтрагента еще до обращения к данным.Такой подход гарантирует не только корректность результата, но и значительно более высокую производительность.
Разница в производительности между двумя подходами может быть колоссальной, особенно на больших базах данных.
ГДЕ: Система сначала поднимает из базы данных огромное количество "лишних" записей, агрегирует их, создает большую временную таблицу в памяти и только потом отбрасывает ненужное. Это нагружает и сервер СУБД, и сервер 1С.Золотое правило работы с запросами к регистрам: всегда используйте параметры виртуальных таблиц для наложения отборов по измерениям. Секция ГДЕ должна использоваться для фильтрации по полям-ресурсам (например, СуммаОстаток > 1000) или по другим вычисляемым полям, которые получаются уже после работы виртуальной таблицы.