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