Почему в запросе 1С не выводятся фактические отпуска и как правильно соединить регистры отпусков?

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

При разработке отчетов по учету кадровых данных и отпусков в конфигурациях 1С:Зарплата и управление персоналом и 1С:Зарплата и кадры государственного учреждения разработчики часто сталкиваются с ситуацией, когда данные в регистрах есть, но запрос возвращает пустые колонки или зависает. Разберем типичные ошибки при обращении к регистрам отпусков и выясним, как построить корректный запрос к информационной базе.

Анализ типовых ошибок при соединении таблиц в запросе

Рассмотрим исходный вариант запроса, в котором возникла проблема с получением количества дней фактического отпуска:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Сотрудники.Ссылка КАК Сотрудник,
    ЗаработанныеПраваНаОтпуска.ДатаНачала КАК ДатаНачала,
    ЗаработанныеПраваНаОтпуска.ДатаОкончания КАК ДатаОкончания,
    ПоложенныеВидыЕжегодныхОтпусков.КоличествоДнейВГод КАК КоличествоДнейВГод,
    ПоложенныеВидыЕжегодныхОтпусков.ВидЕжегодногоОтпуска.Ссылка КАК ВидЕжегодногоОтпускаСсылка,
    ФактическиеОтпуска.Количество КАК Количество
ИЗ
    Справочник.Сотрудники КАК Сотрудники,
    РегистрСведений.ЗаработанныеПраваНаОтпуска КАК ЗаработанныеПраваНаОтпуска,
    РегистрСведений.ПоложенныеВидыЕжегодныхОтпусков КАК ПоложенныеВидыЕжегодныхОтпусков
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ФактическиеОтпуска КАК ФактическиеОтпуска
        ПО (ФактическиеОтпуска.РабочийПериодС >= ДатаНачала)
            И (ФактическиеОтпуска.РабочийПериодПо <= ДатаОкончания)

Проанализируем ключевые проблемы представленного текста:

  1. Неявное соединение через запятую (Декартово произведение): перечисление таблиц Справочник.Сотрудники, РегистрСведений.ЗаработанныеПраваНаОтпуска и РегистрСведений.ПоложенныеВидыЕжегодныхОтпусков в секции ИЗ приводит к эффекту CROSS JOIN. Каждая строка одной таблицы умножается на все строки другой. В результате запрос либо зависает на больших базах, либо возвращает нерелевантные сочетания данных.
  2. Отсутствие связи по измерениям (Сотрудник и Вид отпуска): соединение с регистром накопления ФактическиеОтпуска выполняется только по условию дат, без указания конкретного сотрудника. В таком случае система пытается сопоставить периоды без привязки к физлицу, что приводит к некорректным выборкам или пустым значениям.
  3. Лишнее разыменование ссылок через точку: обращение вида ВидЕжегодногоОтпуска.Ссылка или Сотрудник.Ссылка заставляет платформу создавать дополнительное неявное левое соединение с соответствующим справочником. Если поле уже содержит ссылку, к нему следует обращаться напрямую.
  4. Особенности сопоставления периодов: даты рабочего года (РабочийПериодС и РабочийПериодПо) в типовых конфигурациях динамически сдвигаются при наличии исключаемых периодов (отпуска за свой счет свыше 14 дней в году, отпуска по уходу за ребенком). Прямое строгое сравнение границ дат без учета специфики учета прав часто оставляет выборку пустой.

Исправление структуры запроса

Для исправления ситуации объединим таблицы через явные левые соединения, укажем обязательную связь по ключевому измерению Сотрудник, а также исключим декартово произведение таблиц.

Разберем рабочий вариант запроса с корректными связями:


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

Важные правила работы с отпусками в ЗУП 3 и ЗГУ 3

  1. Группировка и агрегация: регистр ФактическиеОтпуска является регистром накопления. За один и тот же рабочий год сотрудник может брать отпуск несколько раз частями. Чтобы не получить дубли строк, обязательно используем функцию СУММА() и секцию СГРУППИРОВАТЬ ПО.
  2. Обработка отсутствующих значений: для сотрудников, которые еще не использовали отпуск за рабочий год, соединение вернет NULL. Оборачивайте числовые поля в функцию ЕСТЬNULL(..., 0) для корректного отображения и математических расчетов.
  3. Использование виртуальных таблиц: для периодических регистров сведений (например, положенных видов отпусков) следует применять срез последних на дату (СрезПоследних), чтобы получить актуальные настройки нормы дней на сотрудника.
  4. Программный расчет остатков: если требуется получить итоговые остатки отпусков с учетом всех правил законодательства, сдвигов рабочих лет и принципа ФИФО при списании дней, рекомендуется вызывать типовой программный механизм через модуль ОстаткиОтпусков, так как чистый SQL-запрос не всегда может охватить сложную логику перерасчетов.
← На главную