Почему «Срез последних» в запросе 1С возвращает несколько записей для одного измерения?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с регистрами сведений начинающие разработчики часто сталкиваются с ситуацией: в запросе к виртуальной таблице СрезПоследних выбирается только одно измерение (например, Номенклатура), но система возвращает несколько строк для одного и того же товара. На первый взгляд это кажется ошибкой платформы, ведь само название «Срез последних» подразумевает получение одной, самой актуальной записи. Однако это поведение логично и обусловлено архитектурой 1С.

В этой статье мы подробно разберем, как именно функционирует механизм получения среза, почему количество измерений в запросе не влияет на количество возвращаемых строк и как правильно составить запрос, чтобы получить только одну запись в разрезе нужных нам полей.

Разберем фундаментальное правило работы «Среза последних»

Главная ошибка заключается в предположении, что виртуальная таблица СрезПоследних работает аналогично таблицам остатков или оборотов регистров накопления. В регистрах накопления агрегация действительно производится по тем измерениям, которые указаны в полях выборки запроса. Однако в регистре сведений логика иная.

Записи подбираются для каждого уникального сочетания ВСЕХ имеющихся измерений регистра, существующих в метаданных. Если в вашем регистре определено три измерения (например, Номенклатура, ТипЦен и Склад), то платформа найдет наиболее позднюю запись для каждой комбинации этих трех полей.

Рассмотрим пример: у вас есть две записи в регистре цен.

  1. Номенклатура: «Кирпич», Тип цен: «Закупочная», Цена: 10.
  2. Номенклатура: «Кирпич», Тип цен: «Розничная», Цена: 15.

Даже если в запросе вы выберете только поле Номенклатура и Ресурс, система все равно вернет две строки, потому что для платформы это две разные «последние» записи в разрезе всех измерений (Типов цен).

Проанализируем механизм на уровне SQL

Для глубокого понимания процесса важно знать, что происходит «под капотом». Виртуальная таблица не существует в базе данных физически. Платформа 1С динамически генерирует вложенный SQL-запрос. В упрощенном виде алгоритм выглядит так:

  1. Система обращается к физической таблице регистра.
  2. Находит максимальный период для каждой уникальной комбинации измерений, заданных в конфигураторе.
  3. Соединяет полученные наборы данных с основной таблицей для получения значений ресурсов.

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

Как получить только одну запись: Решение №1 (Фильтрация)

Самый простой и правильный способ получить одну строку — это передать в параметры виртуальной таблицы условия по всем измерениям, которые «размножают» результат. Выясним причину детализации (например, это поле ТипЦен) и добавим его в условия.

Пример правильного использования параметров виртуальной таблицы:


ВЫБРАТЬ
    ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, Номенклатура = &Товар И ТипЦен = &Тип) КАК ЦеныНоменклатурыСрезПоследних

Если мы четко задаем значения всех измерений, 1С гарантированно вернет одну запись (или ноль, если данных нет).

Как получить последнюю запись независимо от других измерений: Решение №2 (Соединение)

Иногда задача стоит иначе: нужно узнать, например, когда товар приходил последний раз, не имея значения, на какой склад или какого типа была партия. Если мы просто обратимся к СрезПоследних по номенклатуре, мы получим список по всем складам. Чтобы «схлопнуть» эти данные, используем методику с получением максимальной даты.

Рассмотрим по шагам реализацию через временные таблицы:


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

// Шаг 2: Выбираем данные, соединяя с временной таблицей по товару и дате
ВЫБРАТЬ
    ПартииТоваровСрезПоследних.Товар,
    ПартииТоваровСрезПоследних.Количество
ИЗ
    РегистрСведений.ПартииТоваров.СрезПоследних(&Дата) КАК ПартииТоваровСрезПоследних
ВНУТРЕННЕЕ СОЕДИНЕНИЕ тбПоследниеДаты КАК тбДаты
    ПО ПартииТоваровСрезПоследних.Товар = тбДаты.Товар
    И ПартииТоваровСрезПоследних.Период = тбДаты.МаксПериод

Этот метод позволяет корректно отсечь лишние записи, даже если мы не знаем заранее значения всех измерений.

Использование конструкции ВЫБРАТЬ ПЕРВЫЕ: Решение №3

Если вам нужно получить ровно одну (самую последнюю из последних) запись для конкретного объекта, можно воспользоваться сортировкой. Рассмотрим этот пример:


ВЫБРАТЬ ПЕРВЫЕ 1
    Цены.Цена КАК Цена,
    Цены.Период КАК Период
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, Номенклатура = &Товар) КАК Цены
УПОРЯДОЧИТЬ ПО
    Цены.Период УБЫВ

Этот способ эффективен, когда вам требуется значение только для одного конкретного товара.

Особенности производительности и индексы

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

Также проанализируем ситуацию с левым соединением. Использование виртуальной таблицы СрезПоследних в левом соединении с другой большой таблицей часто приводит к падению производительности. Рекомендуется сначала помещать данные среза во временную таблицу (отфильтровав их максимально возможно), а затем выполнять соединение.

Подведем итоги

Чтобы избежать «дублей» в срезе последних, всегда помните:

Будьте аккуратны при проектировании регистров сведений и всегда учитывайте набор измерений при написании запросов к их виртуальным таблицам.

← На главную