При разработке подсистем расчета заработной платы или любых других сложных вычислений в 1С разработчики часто сталкиваются с регистрами расчета. Механизм получения базы для начислений является одним из самых сложных в платформе. Зачастую, пытаясь получить данные в разрезе конкретных измерений (например, по сотруднику или подразделению), система выдает критическую ошибку на этапе выполнения запроса: «Поле не найдено». Разберем эту ситуацию детально, выясним причину подобного поведения платформы и посмотрим, как правильно настраивать объекты метаданных и запросы, чтобы избежать подобных проблем.
Для начала проанализируем механику работы платформы 1С при обращении к виртуальным таблицам базовых данных регистра расчета. В качестве примера рассмотрим виртуальную таблицу РегистрРасчета.ДополнительныеНачисления.БазаОсновныеНачисления.
Когда мы обращаемся к этой таблице, система динамически собирает данные, опираясь на правила, заданные в конфигураторе (ведущие регистры, базовые виды расчета и так далее). По умолчанию платформа сворачивает все базовые начисления до записей основного регистра, игнорируя детализацию.
Чтобы получить детализацию базовых данных по полям базового регистра, нам необходимо использовать третий параметр виртуальной таблицы — параметр «Разрезы». Рассмотрим пример кода, который часто пытаются использовать разработчики:
ВЫБРАТЬ
ДополнительныеНачисленияБазаОсновныеНачисления.НомерСтроки КАК НомерСтроки,
ДополнительныеНачисленияБазаОсновныеНачисления.РезультатБаза КАК БазаНачислений,
ДополнительныеНачисленияБазаОсновныеНачисления.СотрудникРазрез КАК СотрудникРазрез
ИЗ
РегистрРасчета.ДополнительныеНачисления.БазаОсновныеНачисления(&Измерения, &Измерения, &Разрезы, Регистратор = &Регистратор) КАК ДополнительныеНачисленияБазаОсновныеНачисления
В коде модуля передачи параметра мы задаем массив:
Разрезы = Новый Массив(1);
Разрезы[0] = "Сотрудник";
Запрос.УстановитьПараметр("Разрезы", Разрезы);
Посмотрим на то, что происходит «под капотом». Если в параметр &Разрезы передать массив строк с именами полей (в нашем случае это строка Сотрудник), платформа 1С «на лету» создаст в виртуальной таблице новую колонку. Имя этой новой колонки формируется по строгому правилу: к исходному имени поля добавляется слово «Разрез». Именно так из переданного Сотрудник генерируется доступное для выборки поле СотрудникРазрез.
Если на этапе выполнения или проверки запроса система сообщает, что поле СотрудникРазрез не найдено, это означает лишь одно: платформа не смогла создать эту динамическую колонку. Проанализируем основные причины, почему это происходит.
&Разрезы должен быть строго объектом Массив (содержащим строки) или объектом СписокЗначений (где значение каждого элемента — это Строка). Если вы передадите туда пустой массив, значение другого типа (например, ссылку на конкретного сотрудника из справочника, а не текст) или значение NULL, система не выдаст критического сбоя при передаче параметра. Она просто проигнорирует его. Следовательно, колонки разрезов сгенерированы не будут, и при попытке выбрать поле СотрудникРазрез в секции ВЫБРАТЬ возникнет ошибка.Очень часто разработчики сталкиваются с парадоксом: в программном коде запрос может работать (или падать по другой причине), а при попытке отладить его в стандартной Консоли запросов 1С ошибка «Поле не найдено» появляется постоянно. Разберем по шагам, как правильно настраивать параметры в консоли.
В консоли запросов мы не можем написать программный код инициализации массива. Вместо этого мы используем графический интерфейс:
&Разрезы в колонке «Тип значения» обязательно выберите СписокЗначений.Строка для элемента списка.Сотрудник.Если по ошибке передать в список значений ссылку на конкретного сотрудника (элемент справочника ФизическиеЛица или Сотрудники), а не строковое название поля, запрос не увидит разрезов и выдаст ошибку.
Проанализируем ситуацию, когда параметры в консоли и в коде передаются абсолютно верно (массив строк), но ошибка все равно сохраняется. Именно с этим столкнулся автор исходной проблемы.
Механизм базовых таблиц 1С опирается на строгие правила сопоставления. Виртуальная таблица базы пытается связать записи текущего регистра расчета с записями базового регистра. Эта связь происходит по измерениям. Чтобы система могла корректно сопоставить записи и развернуть их в разрезе (создав поле СотрудникРазрез), типы данных этих измерений должны быть совместимы.
Рассмотрим частую ошибку проектирования: в регистре расчета измерение Сотрудник по ошибке было создано с типом данных Строка, тогда как должно иметь тип СправочникСсылка.ФизическиеЛица (или аналогичный).
Если в основном регистре измерение имеет тип Строка, а в базовом регистре (из которого мы тянем базу) это же по смыслу измерение имеет тип ссылочный, система не сможет корректно связать эти таблицы. Логика платформы блокирует построение разреза по несовместимым полям. В результате динамическое поле не создается, и мы получаем ошибку ненайденного поля.
Как исправить эту проблему:
ДополнительныеНачисления).Сотрудник, Подразделение).СправочникСсылка.ФизическиеЛица, СправочникСсылка.Подразделения).В завершение проанализируем целесообразность использования параметра «Разрезы». Разработчики часто добавляют его «на всякий случай», даже когда этого не требует бизнес-логика.
Важно понимать, что параметр «Разрезы» значительно усложняет текст SQL-запроса, который платформа 1С транслирует к СУБД (MS SQL, PostgreSQL и др.). Использование разрезов заставляет базу данных выполнять дополнительные ресурсоемкие операции соединения таблиц (JOIN) и группировки.
Использовать параметр &Разрезы стоит исключительно в следующих случаях:
Таблица.Сотрудник <> Таблица.СотрудникРазрез — расчет базы по другим сотрудникам, если такая экзотика предусмотрена алгоритмом).Если ваша задача состоит лишь в том, чтобы получить общую итоговую сумму базовых начислений для элементарного расчета (например, вычисление 10% премии от оклада по одному конкретному сотруднику и документу), параметр &Разрезы следует оставлять пустым или вообще пропускать. Это сделает ваш запрос более быстрым и снизит нагрузку на сервер базы данных.