Интервальные регистры ЗУП 3.1 — это непериодические двойники кадровых и расчётных регистров сведений, где каждая запись хранит не дату изменения, а интервал действия значения: ДатаНачала и ДатаОкончания (у открытого интервала — 31.12.3999). Чтобы узнать подразделение или оклад сотрудника на дату, не нужен срез последних — достаточно условия «дата между началом и окончанием». Пишутся такие регистры автоматически при записи основного регистра, вручную их не трогают.

Ниже — зачем это сделано, как устроены интервалы, как писать запросы в доработках и что делать, если интервальные данные разошлись с основными.

Проблема срезов последних

В периодическом регистре сведений хранится момент изменения: «с 01.03 оклад 80 000». Чтобы узнать оклад на 15.04, платформа строит виртуальную таблицу СрезПоследних — ищет последнюю запись до этой даты. Для одного сотрудника на одну дату это дёшево.

В зарплатных задачах так не бывает. Расчёт и отчёты требуют состояния сотрудников на каждый день периода: табель, начисления пропорционально отработанному времени, кадровые отчёты за год. Срез последних на каждую дату для сотен и тысяч сотрудников превращается в тяжёлые запросы с соединениями по МАКСИМУМ(Период), и нагрузка на СУБД растёт кратно.

Интервальные регистры решают это ценой избыточности: те же данные хранятся второй раз, но в форме, удобной для чтения.

Как устроен интервальный регистр

Интервальные регистры ЗУП: точки изменений превращаются в непрерывные интервалы
Интервальные регистры ЗУП: точки изменений превращаются в непрерывные интервалы
Периодический регистрИнтервальный регистр
ПериодичностьПериодический, есть поле ПериодНепериодический
Как хранится состояниеДата изменения и новое значениеИнтервал ДатаНачала — ДатаОкончания и значение
Получение на датуВиртуальная таблица СрезПоследнихУсловие по интервалу
Кто пишетДокументы-регистраторыМеханизм БЗК при записи основного регистра
ПримерКадроваяИсторияСотрудниковКадроваяИсторияСотрудниковИнтервальный

Пример. Сотрудник принят 01.02 с окладом 70 000, с 01.06 оклад повышен до 85 000.

В основном регистре две записи: «01.02 — 70 000» и «01.06 — 85 000». В интервальном тоже две, но иначе:

ДатаНачалаДатаОкончанияЗначение
01.02 00:00:0031.05 23:59:5970 000
01.06 00:00:0031.12.3999 23:59:5985 000

Интервалы идут встык, без пропусков и наложений, — это гарантирует механизм формирования.

Время в ДатаНачала

Тонкость, на которой спотыкаются при доработках. Если в одних сутках несколько изменений (приём и тут же перевод, исправление документа), механизм вытеснения упорядочивает их внутри дня и проставляет время, отличное от 00:00:00. Поэтому параметр даты в запросе приводите к концу дня:

1С
Запрос.УстановитьПараметр("НаДату", КонецДня(ДатаОтчета));

Иначе изменения, внесённые в этот день не в полночь, в выборку не попадут.

Запросы к интервальному регистру

Состояние на дату:

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

Все состояния, действовавшие в периоде, — условие пересечения интервалов:

Запрос 1С
ВЫБРАТЬ
	История.Сотрудник КАК Сотрудник,
	История.Подразделение КАК Подразделение,
	История.Должность КАК Должность,
	История.ДатаНачала КАК ДатаНачала,
	История.ДатаОкончания КАК ДатаОкончания
ИЗ
	РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК История
ГДЕ
	История.Сотрудник = &Сотрудник
	И История.ДатаНачала <= &КонецПериода
	И История.ДатаОкончания >= &НачалоПериода

&КонецПериода — тоже конец дня. Такой запрос вернёт все кадровые изменения, затронувшие период, одним прямым чтением.

Главное преимущество проявляется в соединениях. Таблицу дней периода можно соединить с интервальным регистром по условию «день внутри интервала» и получить состояние сотрудника на каждый день — без подзапросов со срезами.

Прямые запросы или программный интерфейс БЗК

Запросы выше полезны, чтобы понять механизм, и для разовой диагностики. В доработках типовой ЗУП я стараюсь не обращаться к интервальным регистрам напрямую, а использовать программный интерфейс библиотеки БЗК. Например, кадровые данные на дату удобно получать через КадровыйУчет.КадровыеДанныеСотрудников:

1С
// Получает подразделение и должность сотрудников на дату через программный интерфейс БЗК.
КадровыеДанные = КадровыйУчет.КадровыеДанныеСотрудников(Истина, МассивСотрудников,
	"Подразделение,Должность", ДатаОтчета);

Для Каждого Строка Из КадровыеДанные Цикл
	// Строка.Сотрудник, Строка.Подразделение, Строка.Должность
КонецЦикла;

Почему так лучше:

  • внутренняя структура регистров меняется от релиза к релизу, а программный интерфейс сохраняется;
  • интерфейс учитывает права доступа и особенности хранения, которые легко упустить в собственном запросе;
  • после обновления конфигурации меньше шансов, что доработка сломается.

Точный состав параметров смотрите в описании функции в вашем релизе: в БЗК есть варианты, возвращающие таблицу значений, и варианты, создающие временную таблицу в менеджере временных таблиц для использования в своих запросах. Отчёты по кадровым данным я обычно делаю как отчёты на СКД поверх этих механизмов.

Если данные разъехались

Интервальный регистр — по сути кэш, а у любого кэша бывают расхождения с источником. Причины:

  • доработка, которая пишет в основной регистр набором записей в обход документов и механизмов БЗК;
  • прерванная загрузка или обмен данными;
  • ручная правка регистров через обработки редактирования.

Симптомы: кадровый отчёт показывает старое подразделение, расчёт берёт прежний оклад, хотя документ проведён.

Порядок действий:

  1. Перепровести документы сотрудника. При записи регистратора интервалы по этому сотруднику пересчитываются.
  2. Перезаполнить интервальные регистры штатной командой администрирования конфигурации. Для больших баз это долгая операция: планируйте её на нерабочее время и делайте резервную копию.
  3. Программно: в БЗК есть процедуры обновления движений интервального регистра для отбора сотрудников. Имена и параметры отличаются в разных релизах, поэтому перед использованием найдите актуальную процедуру поиском по общим модулям.

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

Интервальный регистр — это кэш для чтения. Пишите в источник, а кэш пусть обновляет механизм, который за него отвечает.

Типичные ошибки разработчика

  • Параметр даты не приведён к концу дня — пропадают изменения последнего дня.
  • Попытка записать интервальный регистр вручную из доработки.
  • Запрос со срезом последних по основному регистру в цикле по дням, хотя есть интервальный двойник.
  • Прямые запросы к интервальным регистрам в тиражируемом расширении, которые ломаются после обновления.
  • Отсутствие пункта «перезаполнить интервальные регистры» в инструкции для поддержки: многие «странные» данные лечатся именно этим.

Итог

  • Интервальные регистры ЗУП 3.1 хранят кадровую и расчётную историю в виде интервалов ДатаНачала — ДатаОкончания.
  • Состояние на дату получается простым условием вместо среза последних, что сильно ускоряет отчёты и расчёт.
  • Регистры ведомые: их формирует механизм БЗК при записи основных регистров, вручную в них не пишут.
  • В запросах приводите даты к концу дня, а в доработках по возможности используйте программный интерфейс БЗК.
  • При расхождениях — перепроведение документов и перезаполнение интервальных регистров, затем поиск доработки-виновника.