Как в тексте запроса 1С передать несколько видов субконто в параметры виртуальной таблицы остатков?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

Анализ технического ограничения платформы

Для начала разберем, почему простая конструкция типа ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры) не работает. В языке запросов 1С функция ЗНАЧЕНИЕ() предназначена для получения ссылки на конкретный одиночный объект метаданных. Параметр ВидыСубконто виртуальных таблиц (Остатки, Обороты, ОстаткиИОбороты) ожидает на вход либо одну ссылку, либо внешний параметр, который платформа интерпретирует как массив или список значений.

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

Способ 1. Использование объединения запросов (ОБЪЕДИНИТЬ ВСЕ)

Этот метод является наиболее "чистым" с точки зрения использования механизмов виртуальных таблиц и производительности. Если нам нужно получить данные по нескольким видам субконто, мы можем составить несколько запросов к одной и той же виртуальной таблице, в каждом из которых укажем свое значение через ЗНАЧЕНИЕ(), и объединим результаты.

Разберем пример, где нам нужны остатки отдельно по Контрагентам и отдельно по Договорам:


ВЫБРАТЬ
    ХозрасчетныйОстатки.Счет КАК Счет,
    ХозрасчетныйОстатки.Субконто1 КАК Аналитика,
    ХозрасчетныйОстатки.СуммаОстаток КАК Сумма
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Остатки(, , ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты), ) КАК ХозрасчетныйОстатки

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

ВЫБРАТЬ
    ХозрасчетныйОстатки.Счет,
    ХозрасчетныйОстатки.Субконто1,
    ХозрасчетныйОстатки.СуммаОстаток
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Остатки(, , ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры), ) КАК ХозрасчетныйОстатки

Важный нюанс: Этот способ идеально подходит, если вам нужно вывести список остатков. Однако он не позволяет получить остатки в разрезе одновременно двух субконто в одной строке (например, Контрагент + Договор), так как платформа при указании одного вида субконто в параметре заполнит только поле Субконто1.

Способ 2. Фильтрация в секции ГДЕ (без указания параметра ВидыСубконто)

Если нам необходимо получить остатки в разрезе нескольких субконто одновременно и мы хотим прописать это в тексте, мы можем оставить параметр ВидыСубконто пустым. В этом случае платформа предоставит доступ к полям Субконто1, Субконто2, Субконто3 (и так далее, в зависимости от настроек регистра) и соответствующим им полям типов ВидСубконто1, ВидСубконто2.

Рассмотрим ситуацию, когда нам нужно отфильтровать данные в секции ГДЕ:


ВЫБРАТЬ
    ХозрасчетныйОстатки.Счет,
    ХозрасчетныйОстатки.Субконто1,
    ХозрасчетныйОстатки.Субконто2,
    ХозрасчетныйОстатки.СуммаОстаток
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Остатки КАК ХозрасчетныйОстатки
ГДЕ
    (ХозрасчетныйОстатки.ВидСубконто1 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты)
        ИЛИ ХозрасчетныйОстатки.ВидСубконто2 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты))
    И (ХозрасчетныйОстатки.ВидСубконто1 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры)
        ИЛИ ХозрасчетныйОстатки.ВидСубконто2 = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры))

В чем опасность этого метода:

  1. Производительность: Когда параметр ВидыСубконто пуст, СУБД выполняет гораздо более тяжелый запрос, считывая все возможные итоги по всем видам субконто. Фильтрация в ГДЕ происходит уже после выборки огромного массива данных.
  2. Порядок субконто: Поля Субконто1, Субконто2 привязаны к физическому порядку видов субконто на конкретном счете. На 60.01 Контрагент может быть первым, а на каком-то другом счете — вторым. Это заставляет писать сложные условия ИЛИ.

Способ 3. Прямое обращение к физическим таблицам (для сложных случаев)

Проанализируем ситуацию, когда стандартные виртуальные таблицы не дают нужной гибкости. Мы можем обратиться к таблице значений субконто и основной таблице регистра. Это сложный путь, который требует ручного расчета остатков (суммирования оборотов), но он позволяет полностью контролировать аналитику в тексте запроса.

Пример логики (упрощенно): мы соединяем таблицу проводок с таблицей субконто дважды — один раз для фильтрации по Контрагенту, второй раз для фильтрации по Договору. Это гарантирует, что мы выберем только те записи, где присутствуют оба вида аналитики.


ВЫБРАТЬ
    ВложенныйЗапрос.Счет,
    ВложенныйЗапрос.Контрагент,
    ВложенныйЗапрос.Договор,
    СУММА(ВложенныйЗапрос.Сумма) КАК СуммаОстаток
ИЗ
    (ВЫБРАТЬ
        Хозрасчетный.СчетДт КАК Счет,
        СубконтоКонтрагенты.Значение КАК Контрагент,
        СубконтоДоговор.Значение КАК Договор,
        Хозрасчетный.Сумма КАК Сумма
    ИЗ
        РегистрБухгалтерии.Хозрасчетный.Субконто КАК СубконтоКонтрагенты
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
            ПО СубконтоКонтрагенты.Регистратор = Хозрасчетный.Регистратор
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Субконто КАК СубконтоДоговор
            ПО СубконтоКонтрагенты.Регистратор = СубконтоДоговор.Регистратор
    ГДЕ
        СубконтоКонтрагенты.Значение ССЫЛКА Справочник.Контрагенты
        И СубконтоДоговор.Значение ССЫЛКА Справочник.ДоговорыКонтрагентов
    ) КАК ВложенныйЗапрос
СГРУППИРОВАТЬ ПО
    ВложенныйЗапрос.Счет,
    ВложенныйЗапрос.Контрагент,
    ВложенныйЗапрос.Договор

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

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

Выясним, как сделать работу удобной, если запрос предназначен для пользователей консоли. Поскольку передать список в ЗНАЧЕНИЕ() нельзя, а заставлять пользователей вручную добавлять массив в параметры не хочется, мы рекомендуем следующее: Используйте временную таблицу для описания видов субконто.

Хотя вы не сможете передать эту временную таблицу в параметр виртуальной таблицы, вы сможете использовать её для наглядного соединения в секции ГДЕ или СОЕДИНЕНИЕ, что упростит чтение кода:


ВЫБРАТЬ ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты) КАК Вид ПОМЕСТИТЬ ВТ_НужныеВиды
ОБЪЕДИНИТЬ ВЫБРАТЬ ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры);

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ХозрасчетныйОстатки.Счет,
    ХозрасчетныйОстатки.Субконто1,
    ХозрасчетныйОстатки.СуммаОстаток
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Остатки КАК ХозрасчетныйОстатки
ГДЕ
    ХозрасчетныйОстатки.ВидСубконто1 В (ВЫБРАТЬ Вид ИЗ ВТ_НужныеВиды)

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

← На главную