Почему не объединяются строки в запросе 1С при использовании ОБЪЕДИНИТЬ и как это исправить

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

При работе с запросами в системе 1С:Предприятие программисты часто сталкиваются с ситуацией, когда данные из разных источников (таблиц или временных таблиц) необходимо собрать в одну результирующую выборку. Казалось бы, оператор ОБЪЕДИНИТЬ должен справиться с этой задачей, «схлопнув» одинаковые записи. Однако на практике мы часто видим в результате две строки вместо одной, где в одной строке данные заполнены, а в другой — на их месте стоит NULL. В этой статье мы подробно разберем, почему так происходит, и как правильно составить запрос, чтобы получить чистый результат без дублей.

Разбор проблемы: теория множеств и логика работы ОБЪЕДИНИТЬ

Рассмотрим ситуацию, с которой столкнулся автор темы. У нас есть две временные таблицы: в одной хранятся данные об авторе версии договора, а в другой — информация о наличии присоединенных файлов. Мы хотим получить таблицу, где для каждого договора будет указан и автор, и сам факт наличия договора в списке.

Проанализируем структуру объединяемых данных:

  1. Первая выборка: {Договор №1, "Иванова Анна Петровна"}
  2. Вторая выборка: {Договор №1, NULL}

Оператор ОБЪЕДИНИТЬ (который по умолчанию работает как UNION DISTINCT в SQL) удаляет только абсолютно идентичные строки. С точки зрения СУБД, строка со ссылкой на пользователя и строка со значением NULL — это две совершенно разные записи. Система не может самостоятельно догадаться, что NULL во второй таблице — это «пустое место», которое нужно заменить данными из первой таблицы. Для нее это уникальная комбинация данных в колонках.

Именно поэтому использование ОБЪЕДИНИТЬ без последующей обработки выдает «лесенку» из данных, где одна и та же сущность (Договор) дублируется несколько раз.

Решение №1: Группировка объединенного результата (Метод МАКСИМУМ)

Наиболее надежный и распространенный способ решения этой задачи — это помещение конструкции ОБЪЕДИНИТЬ во вложенный запрос и последующая группировка по ключевому полю. Разберем этот алгоритм по шагам.

Выясним причину, почему это работает. Функция МАКСИМУМ в языке запросов 1С при работе с ссылочными типами или датами всегда игнорирует NULL, если есть хотя бы одно заполненное значение. Любая ссылка всегда «больше», чем NULL. Таким образом, при группировке система выберет значимое данное (автора) и проигнорирует пустоту.

Посмотрим на пример правильной структуры запроса:


ВЫБРАТЬ
    Т.Договор КАК Договор,
    МАКСИМУМ(Т.АвторВерсии) КАК АвторВерсии
ИЗ (
    ВЫБРАТЬ
        ВТВерсииДоговоровАвтор.Объект КАК Договор,
        ВТВерсииДоговоровАвтор.АвторВерсии КАК АвторВерсии
    ИЗ
        ВТВерсииДоговоровАвтор КАК ВТВерсииДоговоровАвтор

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
        ВТПрисоедФайлы.Договор КАК Договор,
        NULL КАК АвторВерсии
    ИЗ
        ВТПрисоедФайлы КАК ВТПрисоедФайлы
) КАК Т

СГРУППИРОВАТЬ ПО
    Т.Договор

В данном случае мы сначала объединяем все строки через ОБЪЕДИНИТЬ (можно также использовать ОБЪЕДИНИТЬ ВСЕ, так как итоговая группировка всё равно уберет дубликаты, а ОБЪЕДИНИТЬ ВСЕ работает быстрее, так как не делает предварительную проверку на уникальность). Затем мы группируем результат по полю Договор и «схлопываем» автора через функцию МАКСИМУМ.

Решение №2: Использование ПОЛНОЕ СОЕДИНЕНИЕ

Иногда вместо объединения логичнее использовать соединение таблиц. Если нам нужно сопоставить данные из двух временных таблиц по одному ключу (Договору), мы можем применить ЛЕВОЕ СОЕДИНЕНИЕ или ПОЛНОЕ СОЕДИНЕНИЕ.

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


ВЫБРАТЬ
    ЕСТЬNULL(ВТВерсии.Объект, ВТФайлы.Договор) КАК Договор,
    ВТВерсии.АвторВерсии КАК АвторВерсии
ИЗ
    ВТВерсии КАК ВТВерсии
        ПОЛНОЕ СОЕДИНЕНИЕ ВТФайлы КАК ВТФайлы
        ПО ВТВерсии.Объект = ВТФайлы.Договор

Этот подход часто оказывается даже более производительным, чем объединение с последующей группировкой, так как СУБД проще оптимизировать соединение по индексам временных таблиц.

Важные технические нюансы

При работе с такими запросами важно учитывать несколько особенностей платформы 1С:

  1. Типизация полей: Когда мы пишем NULL во второй части объединения, итоговое поле получает составной тип. Если это поле будет использоваться дальше в расчетах или выводиться в отчет, лучше типизировать его. Вместо NULL можно использовать ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка), но помните: пустая ссылка и NULL — это тоже разные значения для оператора ОБЪЕДИНИТЬ!
  2. Функция ВЫРАЗИТЬ: В примере автора используется обращение к регистру ВерсииОбъектов. Поле Объект в этом регистре имеет тип ЛюбаяСсылка. Для оптимизации запроса и возможности обращения к реквизитам через точку обязательно используйте ВЫРАЗИТЬ(Таблица.Объект КАК Справочник.ДоговорыКонтрагентов). Это помогает SQL-серверу заранее понять, к какой физической таблице будет идти обращение.
  3. Избыточные группировки: Рассмотрим код автора в исходном сообщении. Он использует СГРУППИРОВАТЬ ПО внутри каждой части объединения. Если в этих частях и так выбираются уникальные данные или если планируется финальная группировка всего пакета, то внутренние группировки лишние. Они создают дополнительную нагрузку на сервер 1С и сервер баз данных. Старайтесь группировать данные один раз на финальном этапе формирования временной таблицы или результата.

Рекомендации по работе с регистром «ВерсииОбъектов»

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

Для ускорения работы:

Таким образом, мы рассмотрели, что проблема «необъединения» запроса кроется не в ошибке платформы, а в фундаментальных правилах сравнения значений с NULL. Используя вложенные запросы с агрегатными функциями или грамотные соединения, вы всегда сможете получить корректные и очищенные от дублей данные.

← На главную