При разработке механизмов расчета заработной платы в системе 1С:Предприятие программисты часто сталкиваются с типовым паттерном: запрос к основной таблице регистра расчета с использованием ЛЕВОЕ СОЕДИНЕНИЕ к виртуальной таблице ДанныеГрафика. У начинающих разработчиков закономерно возникает вопрос: зачем усложнять запрос и использовать соединение по полю НомерСтроки, если можно обратиться к виртуальной таблице напрямую? Ведь виртуальная таблица, казалось бы, уже содержит всю необходимую информацию.
В этой статье мы подробно разберем, почему прямое обращение к виртуальной таблице является ошибкой в большинстве случаев, и выясним, какие критически важные данные могут быть потеряны при отказе от левого соединения.
Рассмотрим два варианта запроса, которые обсуждались на форуме. Первый вариант — стандартный, с использованием соединения:
ВЫБРАТЬ
ОсновныеНачисления.НомерСтроки КАК НомерСтроки,
ОсновныеНачисления.ВидРасчета.СпособРасчета КАК СпособРасчета,
ЕСТЬNULL(ОсновныеНачисленияДанныеГрафика.ЗначениеПериодДействия, 0) КАК План,
ЕСТЬNULL(ОсновныеНачисленияДанныеГрафика.ЗначениеФактическийПериодДействия, 0) КАК Отработано
ИЗ
РегистрРасчета.ОсновныеНачисления КАК ОсновныеНачисления
ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.ОсновныеНачисления.ДанныеГрафика(
Регистратор = &Регистратор
И ВидРасчета.КатегорияРасчета = &КатегорияРасчета) КАК ОсновныеНачисленияДанныеГрафика
ПО ОсновныеНачисления.НомерСтроки = ОсновныеНачисленияДанныеГрафика.НомерСтроки
ГДЕ
ОсновныеНачисления.Регистратор = &Регистратор
И второй вариант — упрощенный, где обращение идет только к виртуальной таблице:
ВЫБРАТЬ
ОсновныеНачисленияДанныеГрафика.НомерСтроки КАК НомерСтроки,
ОсновныеНачисленияДанныеГрафика.ВидРасчета.СпособРасчета,
ЕСТЬNULL(ОсновныеНачисленияДанныеГрафика.ЗначениеПериодДействия, 0) КАК План,
ЕСТЬNULL(ОсновныеНачисленияДанныеГрафика.ЗначениеФактическийПериодДействия, 0) КАК Отработано
ИЗ
РегистрРасчета.ОсновныеНачисления.ДанныеГрафика(
Регистратор = &Регистратор
И ВидРасчета.КатегорияРасчета = &КатегорияРасчета) КАК ОсновныеНачисленияДанныеГрафика
На первый взгляд результат кажется идентичным. Однако это сходство обманчиво и сохраняется только в «идеальных» условиях, когда все данные заполнены корректно. Проанализируем причины, по которым второй вариант может подвести в реальной работе.
Проанализируем структуру регистра расчета. Не все виды расчета в системе обязательно должны быть привязаны к графику. Например, начисление «Оклад» зависит от отработанных дней и имеет установленный признак Использовать период действия. В то же время «Фиксированная премия» или «Доплата за стаж» могут не зависеть от календаря и не использовать механизм вытеснения.
Если в регистре хранятся разные виды расчета, то записи, для которых период действия не используется, просто отсутствуют в виртуальной таблице ДанныеГрафика. Используя второй вариант запроса, мы полностью исключим такие начисления из результата. ЛЕВОЕ СОЕДИНЕНИЕ из первого примера гарантирует, что мы получим все строки из ОсновныеНачисления, а данные о времени «подтянутся» только там, где они предусмотрены логикой расчета.
Виртуальная таблица ДанныеГрафика не является просто «проекцией» основной таблицы. На уровне СУБД это результат соединения физической таблицы регистра и данных регистра сведений, который назначен в качестве графика. Если в регистре сведений (например, «ГрафикиРаботы») отсутствуют записи на расчетный период (например, кадровик забыл заполнить производственный календарь на новый год), виртуальная таблица вернет пустой результат.
Рассмотрим ситуацию по шагам:
В этом случае прямой запрос к ДанныеГрафика не вернет строку по Иванову вообще. Программа «решит», что начислений нет. Если же мы используем ЛЕВОЕ СОЕДИНЕНИЕ, мы увидим строку Иванова, но в полях План и Отработано будут нули (благодаря ЕСТЬNULL). Это позволит нам выдать пользователю адекватную диагностику: «Внимание, для сотрудника не заполнен график!», вместо того чтобы просто проигнорировать начисление.
Виртуальная таблица ДанныеГрафика рассчитывает значения «на лету», опираясь на фактический период действия. Если запись была полностью вытеснена другой записью (например, сотрудник весь месяц находился на больничном, и его оклад был полностью вытеснен), то в определенных режимах работы виртуальная таблица может вести себя не так, как ожидает разработчик.
Важно понимать разницу:
Для корректного алгоритма расчета (например, когда нам нужно рассчитать базу для другого начисления или проверить полноту ввода данных) нам необходимо видеть исходную строку регистра, даже если ее фактический период равен нулю.
Хотя кажется, что запрос к одной таблице должен работать быстрее, на практике использование основной таблицы в качестве ведущей часто помогает оптимизатору СУБД. Когда мы фильтруем основную таблицу по Регистратору, СУБД сразу ограничивает набор данных. Соединение по индексированному полю НомерСтроки позволяет виртуальной таблице ДанныеГрафика обрабатывать только необходимые записи.
Рассмотрим пример правильного построения запроса с точки зрения производительности:
ВЫБРАТЬ
ТабРегистра.НомерСтроки,
ТабРегистра.Сотрудник,
ЕСТЬNULL(ТабГрафика.ЗначениеПериодДействия, 0) КАК ДниПлан,
ЕСТЬNULL(ТабГрафика.ЗначениеФактическийПериодДействия, 0) КАК ДниФакт
ИЗ
РегистрРасчета.ОсновныеНачисления КАК ТабРегистра
ЛЕВОЕ СОЕДИНЕНИЕ РегистрРасчета.ОсновныеНачисления.ДанныеГрафика(
Регистратор = &Регистратор) КАК ТабГрафика
ПО ТабРегистра.НомерСтроки = ТабГрафика.НомерСтроки
ГДЕ
ТабРегистра.Регистратор = &Регистратор
Здесь ТабРегистра.НомерСтроки выступает надежным ключом связи. Поскольку номера строк уникальны в пределах одного регистратора (или в целом по таблице, в зависимости от настроек), это соединение является максимально эффективным.
Использование левого соединения основной таблицы регистра расчета с виртуальной таблицей данных графика — это не «лишний код», а стандарт надежности. Проанализировав вышесказанное, мы можем выделить ключевые преимущества этого подхода:
1. Полнота данных: Вы никогда не потеряете начисления, которые не используют период действия или график.
2. Диагностика ошибок: Вы сможете отличить отсутствие начисления от отсутствия данных в графике.
3. Корректность расчета: Вы всегда видите исходную запись регистра, даже если она была полностью вытеснена.
4. Соответствие стандартам разработки: Это общепринятый метод в типовых конфигурациях (ЗУП, ERP), что делает ваш код понятным для других разработчиков.
Таким образом, прямой запрос к ДанныеГрафика допустим только в исключительных случаях для решения узких технических задач, где гарантировано наличие всех связей. Во всех остальных случаях — используйте ЛЕВОЕ СОЕДИНЕНИЕ по НомеруСтроки.