Периодичность и режим записи: как устроены регистры сведений 1С 8.3
Содержание
Периодический регистр сведений
хранит значения с привязкой к дате: у каждой записи есть поле Период, и программа умеет отдать значение «на дату». Независимый регистр сведений — это про другое: его записи создаются сами по себе, без документа-регистратора. Обе настройки задаются в конфигураторе на закладке «Данные» свойств регистра.
Частое заблуждение — считать «периодический» и «независимый» противоположностями. Это две разные оси. Свойство «Периодичность» отвечает на вопрос «нужна ли история во времени», свойство «Режим записи» — «кто пишет данные». Регистр может быть периодическим и независимым одновременно (курсы валют), непериодическим и независимым (штрихкоды), периодическим и подчинённым регистратору (цены, которые устанавливает документ).
Зачем нужен регистр сведений и чем он отличается от справочника
Регистр сведений хранит факты в разрезе нескольких измерений. Справочник хранит объекты: у элемента есть ссылка, код, наименование. У записи регистра ссылки нет — её идентифицирует набор ключевых полей.
Структура регистра сведений:
- 📐 Измерения — разрезы, по которым ищут запись: номенклатура, валюта, склад.
- 💰 Ресурсы — то, что хранят: цена, курс, ставка.
- 🏷️ Реквизиты — дополнительная информация к записи, например комментарий или автор изменения.
- 🕒 Стандартные поля —
Период(у периодических),Регистратор,НомерСтроки,Активность(у подчинённых регистратору).
Главное отличие от регистров накопления: регистр сведений не складывает и не вычитает. Он хранит значение «как есть». Новая запись с тем же ключом заменяет старую, а не добавляется к ней.
Если данные нужно накапливать (остатки, обороты) — это регистр накопления. Если нужно знать «какое значение действовало» или «какое значение соответствует сочетанию разрезов» — это регистр сведений.
Периодический регистр сведений: история значений во времени
Периодичность задаётся свойством «Периодичность». Варианты:
| Периодичность | Как хранится Период | Пример применения |
|---|---|---|
| Непериодический | Поля Период нет | Штрихкоды, соответствие кодов, настройки |
| В пределах секунды | Дата и время до секунды | События, статусы с точным временем |
| В пределах дня | Начало дня | Курсы валют, цены |
| В пределах месяца | Начало месяца | Ставки, плановые показатели |
| В пределах квартала | Начало квартала | Квартальные нормативы |
| В пределах года | Начало года | Учётная политика, годовые лимиты |
| По позиции регистратора | Момент времени документа | Значения, которые зависят от порядка документов внутри дня |
Платформа сама приводит дату к началу периода. Если у регистра периодичность «В пределах месяца», а вы записали Период = 15.03, в базе окажется 01.03. Две записи с датами 05.03 и 20.03 для одной номенклатуры превратятся в одну — вторая заменит первую.
Выбирайте периодичность до того, как в регистре появятся данные. Смена периодичности на работающей базе приводит к реструктуризации, а при укрупнении периода записи внутри одного периода схлопываются.
Что даёт периодичность
- 📅 Значение на любую дату. Курс на 1 марта, цена на дату документа — без хранения копий.
- 🔍 Виртуальные таблицы
СрезПоследнихиСрезПервых. Они есть только у периодических регистров. - 🗂️ История изменений. Видно, когда и какое значение действовало.
Вариант «По позиции регистратора» доступен только регистру, подчинённому регистратору. Значение привязывается к моменту времени документа, поэтому два документа в одну секунду не конфликтуют.
Независимый регистр сведений и подчинённый регистратору
Свойство «Режим записи» имеет два значения: «Независимый» и «Подчинение регистратору».
Независимый режим
Записи вводят вручную или кодом, без документа. Пользователь открывает форму списка регистра, добавляет строку, сохраняет. Обработка загрузки курсов пишет в регистр напрямую.
- 🔑 Ключ записи —
Период(если регистр периодический) плюс все измерения. - 🚫 Две записи с одинаковым ключом быть не могут. При попытке записать дубль менеджером записи без замещения платформа выдаст ошибку о существующей записи с такими ключевыми полями.
- ✏️ Отдельную запись можно прочитать, изменить и удалить через менеджер записи.
Где встречается: курсы валют, штрихкоды номенклатуры, контактная информация, настройки пользователей.
Подчинение регистратору
Записи создаёт документ при проведении. Его называют регистратором. Отменили проведение — записи удалились. Пометили документ на удаление и удалили — записи ушли вместе с ним.
- 🔑 Ключ записи —
РегистраториНомерСтроки. - ⚠️ Уникальность сочетания «период + измерения» между разными документами платформа не контролирует. Два документа установят цену на одну дату — в регистре будут обе записи. Следить за этим должен разработчик.
- 🔒 Вручную такие записи не правят: их меняют через документ.
Пример из типовых конфигураций — цены номенклатуры, которые устанавливает документ «Установка цен номенклатуры». Документ хранит, кто и когда поменял цену, а регистр даёт быстрый доступ к актуальному значению.
Если подчинённый регистр начали заполнять ещё и кодом напрямую, без документа — это ошибка проектирования. Такие записи потеряются при перепроведении регистратора или не попадут под его контроль.
Сравнение видов регистров сведений
Четыре возможных сочетания и когда каждое выбирать:
| Сочетание | Ключ записи | Кто пишет | Когда выбирать |
|---|---|---|---|
| Непериодический + независимый | Измерения | Пользователь, код | Справочные соответствия без истории: штрихкоды, настройки |
| Периодический + независимый | Период + измерения | Пользователь, обработки | История значений, которые вводят без первички: курсы, ставки |
| Периодический + подчинённый | Регистратор + номер строки | Документ при проведении | Значения, за изменением которых нужен документ: цены, статусы |
| Непериодический + подчинённый | Регистратор + номер строки | Документ при проведении | Данные документа, которые нужны без истории по дате: служебные связи |
Как выбрать за 30 секунд:
- Нужно знать значение на прошлую дату? Да — периодический. Нет — непериодический.
- Изменение значения должно подтверждаться документом (с датой, автором, возможностью отмены)? Да — подчинение регистратору. Нет — независимый.
- Значение может меняться несколько раз в день? Да — «В пределах секунды» или «По позиции регистратора». Нет — «В пределах дня» или крупнее.
Важность измерений и свойства, которые влияют на работу
Измерения задают ключ записи. Ошибка в их составе — главная причина «пропадающих» данных.
Правило ключа
Если измерений слишком мало, разные факты перезаписывают друг друга. Пример: регистр цен с одним измерением «Номенклатура». Розничная и оптовая цена на одну дату — это один ключ, вторая запись затрёт первую. Нужно второе измерение «Вид цены».
Если измерений слишком много, срез вернёт несколько строк там, где ждали одну. Вынесите в реквизиты то, что не участвует в поиске.
Свойства измерений
- 🔗 «Ведущее» — запись связана с объектом в измерении. Удалили объект — записи регистра удаляются. В форме объекта доступен переход к связанным записям.
- 🎯 «Основной отбор» — по измерению можно устанавливать отбор в наборе записей и в списке. Ставьте его тем измерениям, по которым реально фильтруют.
- 🚷 «Запрет незаполненных значений» — платформа не даст записать пустое значение. Полезно для ключевых измерений вроде валюты.
- ⚡ «Индексировать» — дополнительный индекс для отборов и соединений по измерению.
Свойства регистра
- 📑 «Основной отбор по периоду» — у периодических регистров позволяет отбирать записи по дате в наборе и в списке.
- 🚀 Итоги среза последних и среза первых. Платформа может хранить актуальные значения в отдельной таблице. Запрос к
СрезПоследнихна текущую дату тогда читает готовый результат, а не перебирает историю. Имеет смысл для больших регистров с частыми запросами «на сейчас».
Запись в регистр сведений из встроенного языка
Имена объектов в примерах условные: ЦеныТоваров, ШтрихкодыТоваров. Подставьте свои.
Менеджер записи — одна запись независимого регистра
МенеджерЗаписи = РегистрыСведений.ЦеныТоваров.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = НачалоДня(ТекущаяДатаСеанса());
МенеджерЗаписи.Номенклатура = Товар;
МенеджерЗаписи.ВидЦены = ВидЦены;
МенеджерЗаписи.Цена = 1250;
МенеджерЗаписи.Записать(); // по умолчанию Замещать = Истина
Записать() с параметром по умолчанию заменяет существующую запись с тем же ключом. Записать(Ложь) при существующей записи вызовет ошибку — так удобно ловить случайные дубли.
Чтобы изменить запись, сначала заполните ключевые поля, вызовите Прочитать(), проверьте Выбран(), затем меняйте ресурсы и записывайте.
Набор записей — много строк сразу
Набор = РегистрыСведений.ШтрихкодыТоваров.СоздатьНаборЗаписей();
Набор.Отбор.Номенклатура.Установить(Товар);
Набор.Прочитать();
Запись = Набор.Добавить();
Запись.Номенклатура = Товар;
Запись.Штрихкод = "4601234567890";
Набор.Записать(); // заменит все записи, попавшие под отбор
Набор с параметром замещения по умолчанию удаляет всё, что попадает под отбор, и пишет своё содержимое. Если не вызвать Прочитать() перед Добавить(), старые штрихкоды этого товара исчезнут. Если не установить отбор вовсе, перезапишется весь регистр.
Движения документа — подчинённый регистр
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.ЦеныТоваров.Записывать = Истина;
Для Каждого Строка Из Товары Цикл
Движение = Движения.ЦеныТоваров.Добавить();
Движение.Период = Дата;
Движение.Номенклатура = Строка.Номенклатура;
Движение.ВидЦены = ВидЦены;
Движение.Цена = Строка.Цена;
КонецЦикла;
КонецПроцедуры
Записывать = Истина говорит платформе записать движения после обработчика. Старые движения этого регистратора при перепроведении заменяются.
Быстрое чтение без запроса
У менеджера периодического регистра есть ПолучитьПоследнее() и ПолучитьПервое(). Они возвращают структуру ресурсов:
Отбор = Новый Структура("Номенклатура, ВидЦены", Товар, ВидЦены);
Значения = РегистрыСведений.ЦеныТоваров.ПолучитьПоследнее(ТекущаяДатаСеанса(), Отбор);
Цена = Значения.Цена;
Для одного значения это удобно. Для цен по сотне строк используйте запрос: вызов в цикле — это сотня обращений к базе.
Срезы последних и первых в запросах
СрезПоследних(Период, Условие) возвращает по каждому сочетанию измерений последнюю запись с датой не позже указанной. СрезПервых — первую запись не раньше указанной даты.
ВЫБРАТЬ
Цены.Номенклатура,
Цены.Цена
ИЗ
РегистрСведений.ЦеныТоваров.СрезПоследних(
&ДатаЦен,
ВидЦены = &ВидЦены
И Номенклатура В (&СписокТоваров)) КАК Цены
Условие — в параметрах или в ГДЕ
Самая частая ошибка в запросах к срезу — не понимать, когда срабатывает условие. Условие в параметре виртуальной таблицы отбирает записи до вычисления среза. Условие в ГДЕ применяется после.
Для отбора по измерениям результат одинаковый, но условие в параметрах быстрее: СУБД сразу работает с меньшим числом строк. Поэтому отборы по измерениям всегда ставьте в параметр «Условие».
Для отбора по ресурсам и реквизитам результат разный. Пример: у товара измерение одно — «Номенклатура», а валюта цены хранится в реквизите.
- 1 марта записана цена 1 000 руб.
- 10 марта — цена 12 USD.
- Запрос на 15 марта с условием
Валюта = &Рубльв параметрах вернёт 1 000 руб. от 1 марта: это последняя рублёвая запись. - Тот же запрос с условием в
ГДЕне вернёт товар: последняя запись в долларах, иГДЕеё отбросит.
Какой вариант правильный, решает задача. «Какая цена действует сейчас и в рублях ли она» — ГДЕ. «Какая была последняя рублёвая цена» — параметр. Ошибка в том, чтобы поставить условие наугад.
Дата среза и время
Если регистр «В пределах секунды», а в &ДатаЦен передана дата без времени (15.03 00:00:00), записи этого дня с более поздним временем в срез не попадут. Передавайте КонецДня(Дата) или точный момент документа.
Срез на дату каждого документа
Виртуальная таблица принимает одну дату. Когда нужны цены на дату каждого документа в выборке, СрезПоследних не подходит. Решение — соединение с самой таблицей регистра через максимальный период:
ВЫБРАТЬ
Стр.Ссылка КАК Документ,
Стр.Номенклатура КАК Номенклатура,
МАКСИМУМ(Цены.Период) КАК Период
ПОМЕСТИТЬ ВТ_Периоды
ИЗ
Документ.ЗаказКлиента.Товары КАК Стр
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныТоваров КАК Цены
ПО Цены.Номенклатура = Стр.Номенклатура
И Цены.ВидЦены = &ВидЦены
И Цены.Период <= Стр.Ссылка.Дата
ГДЕ
Стр.Ссылка В (&Документы)
СГРУППИРОВАТЬ ПО
Стр.Ссылка,
Стр.Номенклатура
;
ВЫБРАТЬ
ВТ.Документ,
ВТ.Номенклатура,
Цены.Цена
ИЗ
ВТ_Периоды КАК ВТ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныТоваров КАК Цены
ПО Цены.Период = ВТ.Период
И Цены.Номенклатура = ВТ.Номенклатура
И Цены.ВидЦены = &ВидЦены
Первый пакет находит для каждой строки дату последней действовавшей цены. Второй достаёт саму цену. Отбор по документам в ГДЕ первого пакета обязателен, иначе СУБД соединит всю табличную часть со всей историей цен.
Для подчинённого регистра этот приём вернёт две строки, если два документа поставили цену на одну и ту же дату. Добавьте в ключ соединения ещё одно поле или исключите такие дубли на этапе проведения.
Работа с физической таблицей
Без виртуальной таблицы к регистру можно обратиться напрямую: РегистрСведений.ЦеныТоваров. Так получают историю целиком — например, отчёт «как менялась цена за квартал» с отбором Период МЕЖДУ &Начало И &Конец.
Частые вопросы
Можно ли сделать непериодический регистр периодическим, если данные уже есть?
Почему в независимом регистре нельзя добавить вторую запись на ту же дату?
Можно ли поменять режим записи с независимого на подчинение регистратору?
Есть ли у непериодического регистра срез последних?
СрезПоследних и СрезПервых есть только у периодических регистров. У непериодического регистра запрос идёт к основной таблице.Чем ресурс отличается от реквизита регистра сведений?
ПолучитьПоследнее() и ПолучитьПервое() возвращают только ресурсы.