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