← Назад к вопросам

Выбор работающих сотрудников на дату

2.0 Middle🔥 181 комментариев
#Запросы и оптимизация

Условие

Напишите запрос для выбора сотрудников, которые работали в организации на определённую дату.

Дано:

  • Справочник "Сотрудники"
  • Регистр сведений "КадроваяИстория" (периодический) с измерением "Сотрудник" и ресурсом "Состояние" (Работает/Уволен)

Требования

  • Получить срез последних записей на указанную дату
  • Отфильтровать только записи со статусом "Работает"

Параметр запроса

  • &ДатаОтчёта — дата, на которую нужно получить список работающих сотрудников

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Выбор работающих сотрудников на дату

Решение с СРЕЗОМ ПОСЛЕДНИХ

Функция ПолучитьСотрудниковНаДату(ДатаОтчёта, Организация = Неопределено)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    КадроваяИстория.Сотрудник,
    |    КадроваяИстория.Состояние
    |ИЗ РегистрСведений.КадроваяИстория.СрезПоследних(&ДатаОтчёта, ) КАК КадроваяИстория
    |ГДЕ КадроваяИстория.Состояние = ЗНАЧЕНИЕ(Перечисления.СостояниеСотрудника.Работает)";
    
    Запрос.УстановитьПараметр("ДатаОтчёта", ДатаОтчёта);
    
    Результат = Запрос.Выполнить();
    Возврат Результат.Выгрузить();
    
КонецФункции

Объяснение:

  • СрезПоследних() — встроенная функция 1С, которая берёт последнюю запись по каждому сотруднику на указанную дату
  • Параметры: дата, фильтры (пусто = без фильтров)
  • Фильтруем по состоянию "Работает"
  • Результат — все сотрудники, работавшие на эту дату

Более сложный вариант с условиями

Функция ПолучитьСотрудниковСУсловиями(ДатаОтчёта, Организация, Подразделение = Неопределено)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    КадроваяИстория.Сотрудник,
    |    Сотрудники.Наименование,
    |    Сотрудники.Подразделение,
    |    Сотрудники.Должность,
    |    КадроваяИстория.Состояние
    |ИЗ РегистрСведений.КадроваяИстория.СрезПоследних(&ДатаОтчёта, ) КАК КадроваяИстория
    |    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Сотрудники
    |        ПО КадроваяИстория.Сотрудник = Сотрудники.Ссылка
    |ГДЕ КадроваяИстория.Состояние = ЗНАЧЕНИЕ(Перечисления.СостояниеСотрудника.Работает)
    |    И Сотрудники.Организация = &Организация";
    
    Если ЗначениеЗаполнено(Подразделение) Тогда
        Запрос.Текст = Запрос.Текст + " И Сотрудники.Подразделение = &Подразделение";
    КонецЕсли;
    
    Запрос.УстановитьПараметр("ДатаОтчёта", ДатаОтчёта);
    Запрос.УстановитьПараметр("Организация", Организация);
    Если ЗначениеЗаполнено(Подразделение) Тогда
        Запрос.УстановитьПараметр("Подразделение", Подразделение);
    КонецЕсли;
    
    Результат = Запрос.Выполнить();
    Возврат Результат.Выгрузить();
    
КонецФункции

Особенности:

  • ВНУТРЕННЕЕ СОЕДИНЕНИЕ — берёт только сотрудников, которые есть в справочнике и в истории
  • Дополнительные фильтры по организации и подразделению
  • Возвращает полную информацию о сотруднике

Вариант с диапазоном дат

Если нужны сотрудники, работавшие на начало периода:

Функция ПолучитьСотрудниковНаПериод(НачалоПериода, КонецПериода)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    КадроваяИстория.Сотрудник
    |ИЗ РегистрСведений.КадроваяИстория КАК КадроваяИстория
    |ГДЕ КадроваяИстория.Период >= &НачалоПериода
    |    И КадроваяИстория.Период <= &КонецПериода
    |    И КадроваяИстория.Состояние = ЗНАЧЕНИЕ(Перечисления.СостояниеСотрудника.Работает)";
    
    Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
    Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
    
    Результат = Запрос.Выполнить();
    Возврат Результат.Выгрузить();
    
КонецФункции

Альтернатива с проверкой дат найма и увольнения

Если информация хранится в самом справочнике (ДатаПриема, ДатаУвольнения):

Функция ПолучитьСотрудниковПроверкойДатДиректно(ДатаОтчёта)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Сотрудники.Ссылка,
    |    Сотрудники.Наименование,
    |    Сотрудники.ДатаПриема,
    |    Сотрудники.ДатаУвольнения
    |ИЗ Справочник.Сотрудники КАК Сотрудники
    |ГДЕ Сотрудники.ДатаПриема <= &ДатаОтчёта
    |    И (Сотрудники.ДатаУвольнения = '00010101' ИЛИ Сотрудники.ДатаУвольнения > &ДатаОтчёта)";
    
    Запрос.УстановитьПараметр("ДатаОтчёта", ДатаОтчёта);
    
    Результат = Запрос.Выполнить();
    Возврат Результат.Выгрузить();
    
КонецФункции

Объяснение:

  • ДатаПриема <= ДатаОтчёта — сотрудник уже приняёт на дату отчёта
  • ДатаУвольнения = '00010101' — не был уволен (пустая дата в 1С = 1 января 0001 года)
  • ДатаУвольнения > ДатаОтчёта — был уволен ПОСЛЕ даты отчёта

Проверка в 1С:ЗУП (реальный пример)

Функция ПолучитьСписокСотрудников(ДатаОтчёта) Экспорт
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    СоседокПоследних.Сотрудник,
    |    Справочник.Сотрудники.Наименование,
    |    Справочник.Сотрудники.ЛичныйНомер,
    |    СоседокПоследних.СтатусЗанятости
    |ИЗ РегистрСведений.СотрудникиОрганизаций.СрезПоследних(&ДатаОтчёта, ) КАК СоседокПоследних
    |    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Справочник.Сотрудники
    |        ПО СоседокПоследних.Сотрудник = Справочник.Сотрудники.Ссылка
    |ГДЕ СоседокПоследних.СтатусЗанятости = ЗНАЧЕНИЕ(Перечисления.СтатусЗанятости.РазрешеноТрудиться)";
    
    Запрос.УстановитьПараметр("ДатаОтчёта", ДатаОтчёта);
    
    Результат = Запрос.Выполнить();
    Возврат Результат.Выгрузить();
    
КонецФункции

Ключевые моменты

ПодходКогда использоватьПлюсыМинусы
СрезПоследнихИстория в регистреБыстро, точноНужен периодический регистр
ВНУТРЕННЕЕ СОЕДИНЕНИЕС доп. информациейМного данныхСложнее запрос
Проверка датИстория в справочникеПростоМедленнее, менее гибко
Диапазон датПо периодамГибкоМожет вернуть дубли

Оптимальное решение для production

Функция ПолучитьСотрудниковНаДату(ДатаОтчёта, Организация) Экспорт
    
    // Кэшируем результат на день
    КлючКэша = "СотрудникиНа" + Формат(ДатаОтчёта, "ДФ=yyyymmdd") + Организация.УникальныйИдентификатор();
    
    Если НЕ ЗначениеЗаполнено(Неопределено) Тогда // Проверка кэша
        Возврат ПолучитьИзКэша(КлючКэша);
    КонецЕсли;
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    КадроваяИстория.Сотрудник,
    |    Сотрудники.Наименование
    |ИЗ РегистрСведений.КадроваяИстория.СрезПоследних(&ДатаОтчёта, ) КАК КадроваяИстория
    |    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Сотрудники
    |        ПО КадроваяИстория.Сотрудник = Сотрудники.Ссылка
    |        И Сотрудники.Организация = &Организация
    |ГДЕ КадроваяИстория.Состояние = ЗНАЧЕНИЕ(Перечисления.СостояниеСотрудника.Работает)
    |УПОРЯДОЧИТЬ ПО Сотрудники.Наименование";
    
    Запрос.УстановитьПараметр("ДатаОтчёта", ДатаОтчёта);
    Запрос.УстановитьПараметр("Организация", Организация);
    
    Результат = Запрос.Выполнить().Выгрузить();
    СохранитьВКэш(КлючКэша, Результат);
    
    Возврат Результат;
    
КонецФункции

Рекомендация: используйте СрезПоследних с ВНУТРЕННИМ СОЕДИНЕНИЕМ — это самый быстрый и надёжный способ в 1С.