В процессе разработки на платформе 1С:Предприятие часто возникает задача получения самых ранних данных из периодического регистра сведений. Например, нам может потребоваться узнать дату первой котировки для каждой валюты, дату первого изменения цены товара или момент самого первого поступления сотрудника на работу. Несмотря на кажущуюся простоту, эта задача имеет несколько вариантов решения, каждый из которых обладает своими особенностями в плане производительности и точности данных.
В данной статье мы подробно разберем, как правильно составить запрос для выбора первой записи регистра сведений, проанализируем различные подходы и выясним, какой из них лучше использовать в конкретных ситуациях.
Самым очевидным и простым способом получения первых записей является использование виртуальной таблицы СрезПервых. Эта таблица специально предназначена для получения наиболее ранних записей на определенный момент времени.
Проанализируем особенности этого метода. Если нам нужно получить самые первые записи за всю историю ведения учета, мы можем вызвать виртуальную таблицу без указания параметра Период или передать в него пустую дату (01.01.0001).
Рассмотрим пример запроса:
ВЫБРАТЬ
КурсыВалютСрезПервых.Валюта КАК Валюта,
КурсыВалютСрезПервых.Период КАК ДатаПервойКотировки,
КурсыВалютСрезПервых.Курс КАК Курс
ИЗ
РегистрСведений.КурсыВалют.СрезПервых(&ПустаяДата, ) КАК КурсыВалютСрезПервых
Преимущества метода:
Однако стоит учитывать, что на огромных объемах данных виртуальная таблица может работать медленнее, чем прямой запрос к физической таблице, так как СУБД выполняет сложный вложенный запрос для формирования среза.
Если нам необходимо получить только дату первой записи и сами измерения (без ресурсов), либо если мы хотим максимально оптимизировать запрос, можно обратиться к физической таблице регистра напрямую. Рассмотрим этот подход подробнее.
Суть метода заключается в использовании агрегатной функции МИНИМУМ(Период) с группировкой по всем необходимым измерениям. Посмотрим на пример:
ВЫБРАТЬ
КурсыВалют.Валюта КАК Валюта,
МИНИМУМ(КурсыВалют.Период) КАК Период
ИЗ
РегистрСведений.КурсыВалют КАК КурсыВалют
ГРУППИРОВАТЬ ПО
КурсыВалют.Валюта
Этот запрос эффективно использует индекс по периоду и измерениям, который 1С автоматически создает для периодических регистров. Но у этого метода есть существенное ограничение: мы не можем просто так добавить в этот запрос ресурсы (например, сам Курс), так как они не входят в группировку.
Для того чтобы получить значения ресурсов (курс, кратность и т.д.) на дату самой первой записи, мы объединим подходы. Этот метод считается наиболее гибким и часто используется опытными разработчиками.
Разберем алгоритм по шагам:
Посмотрим на пример реализации такого запроса:
// Шаг 1: Получаем минимальные даты во временную таблицу
ВЫБРАТЬ
КурсыВалют.Валюта КАК Валюта,
МИНИМУМ(КурсыВалют.Период) КАК Период
ПОМЕСТИТЬ ВТ_ПервыеДаты
ИЗ
РегистрСведений.КурсыВалют КАК КурсыВалют
ГРУППИРОВАТЬ ПО
КурсыВалют.Валюта
;
// Шаг 2: Соединяем с основной таблицей для получения ресурсов
ВЫБРАТЬ
ВТ_ПервыеДаты.Валюта,
ВТ_ПервыеДаты.Период КАК ДатаПервойКотировки,
КурсыВалют.Курс КАК Курс
ИЗ
ВТ_ПервыеДаты КАК ВТ_ПервыеДаты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
ПО ВТ_ПервыеДаты.Валюта = КурсыВалют.Валюта
И ВТ_ПервыеДаты.Период = КурсыВалют.Период
Важное замечание: Метод с соединением по периоду может привести к дублированию строк, если в регистре разрешены записи с одинаковым периодом в пределах одной секунды (хотя для большинства регистров с периодичностью «в пределах секунды» это невозможно, для независимых регистров это иногда случается).
Проанализируем ситуацию, когда для одного измерения в одну и ту же секунду были введены две записи. Метод с МИНИМУМ(Период) вернет одну дату, но при соединении с основной таблицей по этой дате вы получите две строки вместо одной.
Чтобы гарантированно выбрать строго одну «самую первую» запись, профессионалы рекомендуют использовать дополнительные критерии сортировки:
Также для краткости кода можно использовать оператор В (ВЫБРАТЬ...) с кортежем полей в условии ГДЕ. Это позволяет избежать явного создания временных таблиц в тексте запроса:
ВЫБРАТЬ
Рег.Валюта,
Рег.Период,
Рег.Курс
ИЗ
РегистрСведений.КурсыВалют КАК Рег
ГДЕ
(Рег.Валюта, Рег.Период) В
(ВЫБРАТЬ
Т.Валюта,
МИНИМУМ(Т.Период)
ИЗ
РегистрСведений.КурсыВалют КАК Т
ГРУППИРОВАТЬ ПО Т.Валюта)
Выясним, от чего зависит скорость выполнения таких запросов. В периодических регистрах 1С автоматически создает индекс Период + Измерения. Если ваш запрос строится по физической таблице через МИНИМУМ(Период), СУБД эффективно использует этот индекс.
Если вы планируете часто делать выборки «первой записи» по определенному измерению (например, по валюте), убедитесь, что это измерение стоит первым в списке измерений регистра в конфигураторе. Порядок измерений напрямую влияет на эффективность использования индексов в SQL.
Резюмируем:
СрезПервых.МИНИМУМ(Период) с группировкой.Регистратор или НомерЗаписи.