Как в запросе 1С выбрать последнюю запись при наличии дублей по определенным полям?

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

В практике разработки на платформе 1С часто возникает задача выбора «последней» записи из набора данных, сгруппированных по определенному признаку. Классический пример: нам нужно получить список товаров с их ценами из документов поступления, но если один и тот же товар поступал по одной и той же цене несколько раз, в отчет должен попасть только самый свежий документ. Использование простого оператора РАЗЛИЧНЫЕ в данном случае невозможно, так как нам необходимо вывести ссылку на конкретный документ, которая всегда уникальна.

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

Метод 1: Использование временных таблиц и группировки (основной способ)

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

Шаг 1: Поиск максимального значения времени

Проанализируем ситуацию: для каждой уникальной пары «Товар» и «Цена» нам нужно найти самую позднюю дату поступления. Для этого мы создаем временную таблицу и используем агрегатную функцию МАКСИМУМ.


ВЫБРАТЬ
    ПоступлениеТоваров.Товар КАК Товар,
    ПоступлениеТоваров.Цена КАК Цена,
    МАКСИМУМ(ПоступлениеТоваров.Дата) КАК МаксДата
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
    Документ.ПоступлениеТоваров КАК ПоступлениеТоваров
СГРУППИРОВАТЬ ПО
    ПоступлениеТоваров.Товар,
    ПоступлениеТоваров.Цена
;

Шаг 2: Получение ссылки на документ через соединение

Теперь, когда у нас есть временная таблица ВТ_МаксимальныеДаты, мы можем соединить её с исходной таблицей документов по полям «Товар», «Цена» и «Дата». Рассмотрим, как это выглядит в итоговом запросе:


ВЫБРАТЬ
    ДокументТ.Товар,
    ДокументТ.Цена,
    ДокументТ.Ссылка КАК ДокументПоступления,
    ДокументТ.Дата
ИЗ
    Документ.ПоступлениеТоваров КАК ДокументТ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МаксимальныеДаты КАК ВТ
ПО
    ДокументТ.Товар = ВТ.Товар
    И ДокументТ.Цена = ВТ.Цена
    И ДокументТ.Дата = ВТ.МаксДата

Метод 2: Обработка документов с одинаковой датой

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

Выясним, почему это работает: ссылки (GUID) в 1С можно сравнивать между собой. Выбирая максимальную ссылку среди документов с одинаковой датой, мы гарантированно получаем только одну запись. Изменим наш запрос:


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

Важное замечание: Для повышения производительности при работе с большими объемами данных обязательно индексируйте временные таблицы по полям соединения. Для этого используйте ключевое слово ИНДЕКСИРОВАТЬ ПО после описания временной таблицы.

Метод 3: Левое соединение с проверкой на NULL (SQL-подход)

Существует альтернативный способ решения задачи одним запросом без использования временных таблиц. Рассмотрим логику: мы выбираем документ из таблицы «А» и пытаемся найти в этой же таблице документ «Б» с таким же товаром и ценой, но с большей датой. Если такой документ «Б» не найден (результат соединения ЕСТЬ NULL), значит документ «А» — самый поздний.


ВЫБРАТЬ
    Т1.Товар,
    Т1.Цена,
    Т1.Ссылка,
    Т1.Дата
ИЗ
    Документ.ПоступлениеТоваров КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваров КАК Т2
ПО
    Т1.Товар = Т2.Товар
    И Т1.Цена = Т2.Цена
    И Т1.Дата < Т2.Дата
ГДЕ
    Т2.Ссылка ЕСТЬ NULL

Этот метод элегантен, но имеет свои недостатки. На огромных таблицах он может работать медленнее, чем метод с временными таблицами, из-за специфики оптимизации планов запросов в некоторых СУБД. Кроме того, он также требует дополнительной обработки случая с одинаковыми датами (через сравнение Т1.Ссылка < Т2.Ссылка).

Метод 4: Использование Момента времени

Для более точного позиционирования в 1С существует объект МоментВремени, который включает в себя и дату, и ссылку. В языке запросов мы можем использовать поле МоментВремени для упорядочивания, однако агрегатные функции, такие как МАКСИМУМ, лучше работают с примитивными типами. Если вы работаете не с документами напрямую, а с регистрами, всегда используйте виртуальную таблицу СрезПоследних.

Рассмотрим, почему это архитектурно правильнее. Если задача «получить последнюю цену товара» возникает регулярно, это повод создать периодический регистр сведений. Платформа 1С оптимизирует запросы к срезу последних на уровне базы данных, что работает в десятки раз быстрее ручных группировок документов.

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

Мы проанализировали основные подходы к выбору последней записи в запросе. Подведем итоги совместной работы:

  1. Самый надежный способ — использование временной таблицы для поиска МАКСИМУМ(Дата) и последующее ВНУТРЕННЕЕ СОЕДИНЕНИЕ.
  2. Для исключения дублей при совпадении времени используйте дополнительную группировку по МАКСИМУМ(Ссылка).
  3. Для оптимизации не забывайте про индексацию полей «Товар» и «Цена» во временных таблицах.
  4. Архитектурный совет: если отчет строится часто, рассмотрите возможность переноса данных в регистр сведений для использования СрезПоследних.

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

← На главную