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