В практике разработчика 1С часто возникает задача сравнения двух наборов данных. Например, нужно найти товары, которые есть в первом регистре, но отсутствуют во втором, или получить полный список уникальных позиций, которые не имеют пары в обеих таблицах (так называемая симметрическая разность). Рассмотрим подробнее несколько эффективных способов решения этой задачи, проанализируем их плюсы и минусы, а также разберем технические нюансы оптимизации.
Этот метод является одним из самых простых и надежных, особенно когда нам нужно найти записи, которые встречаются ровно один раз во всей совокупности данных из двух таблиц. Разберем этот подход по шагам:
ОБЪЕДИНИТЬ ВСЕ.Товар).ИМЕЮЩИЕ мы отсекаем те записи, количество которых больше единицы.Посмотрим на пример кода:
ВЫБРАТЬ
Регистр1.Товар КАК Товар
ПОМЕСТИТЬ ВТ_ВсеТовары
ИЗ
РегистрСведений.Регистр1 КАК Регистр1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Регистр2.Товар
ИЗ
РегистрСведений.Регистр2 КАК Регистр2
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ВсеТовары.Товар КАК Товар
ИЗ
ВТ_ВсеТовары КАК ВТ_ВсеТовары
СГРУППИРОВАТЬ ПО
ВТ_ВсеТовары.Товар
ИМЕЮЩИЕ
КОЛИЧЕСТВО(ВТ_ВсеТовары.Товар) = 1
Важный нюанс: Этот метод корректно работает только в том случае, если в исходных таблицах записи уже уникальны. Если внутри Регистр1 один и тот же товар встречается дважды, условие Количество = 1 его отсеет, даже если в Регистр2 его нет. Чтобы избежать этого, предварительно используйте ВЫБРАТЬ РАЗЛИЧНЫЕ в каждой части объединения.
Если задача стоит более узко — найти только те товары, которые есть в первой таблице, но отсутствуют во второй, — идеально подходит ЛЕВОЕ СОЕДИНЕНИЕ. Проанализируем ситуацию: при левом соединении для записей из левой таблицы, которым не нашлось соответствия в правой, поля правой таблицы будут заполнены значением NULL. Это и есть наш маркер различия.
Рассмотрим пример запроса:
ВЫБРАТЬ
Т1.Товар КАК Товар
ИЗ
РегистрСведений.Регистр1 КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Регистр2 КАК Т2
ПО Т1.Товар = Т2.Товар
ГДЕ
Т2.Товар ЕСТЬ NULL
Если же нам нужно получить "разные" значения из обеих таблиц (симметрическую разность), мы можем объединить два таких запроса:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Т1.Товар КАК Товар
ИЗ
РегистрСведений.Регистр1 КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Регистр2 КАК Т2
ПО Т1.Товар = Т2.Товар
ГДЕ
Т2.Товар ЕСТЬ NULL
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ РАЗЛИЧНЫЕ
Т2.Товар
ИЗ
РегистрСведений.Регистр2 КАК Т2
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Регистр1 КАК Т1
ПО Т2.Товар = Т1.Товар
ГДЕ
Т1.Товар ЕСТЬ NULL
Оператор ПОЛНОЕ СОЕДИНЕНИЕ позволяет выполнить задачу в рамках одного пакета запроса без использования объединений (UNION). Мы соединяем две таблицы по ключевому полю и в секции ГДЕ указываем, что нас интересуют только те строки, где либо в первой, либо во второй таблице значение не определено (ЕСТЬ NULL).
Выясним, как это выглядит на практике:
ВЫБРАТЬ
ЕСТЬNULL(Т1.Товар, Т2.Товар) КАК Товар
ИЗ
РегистрСведений.Регистр1 КАК Т1
ПОЛНОЕ СОЕДИНЕНИЕ РегистрСведений.Регистр2 КАК Т2
ПО Т1.Товар = Т2.Товар
ГДЕ
(Т1.Товар ЕСТЬ NULL ИЛИ Т2.Товар ЕСТЬ NULL)
Особенности производительности: Следует помнить, что ПОЛНОЕ СОЕДИНЕНИЕ может работать медленнее на СУБД PostgreSQL. Также использование условия ИЛИ в секции ГДЕ часто мешает оптимизатору запросов эффективно использовать индексы. Для высоконагруженных систем метод с ОБЪЕДИНИТЬ (Способ 2) часто оказывается предпочтительнее.
Это продвинутый метод, который часто используют опытные разработчики для сверки больших объемов данных. Он позволяет не только найти отсутствие записей, но и выявить расхождения в количестве, если это необходимо. Разберем по шагам:
Проанализируем результат: если сумма равна 0, значит товар есть в обеих таблицах в равном количестве. Если сумма отлична от нуля (1 или -1), значит товар уникален для одной из таблиц.
ВЫБРАТЬ
Т.Товар КАК Товар,
СУММА(Т.Счетчик) КАК ИтоговыйСчетчик
ИЗ
(ВЫБРАТЬ Товар, 1 КАК Счетчик ИЗ РегистрСведений.Регистр1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Товар, -1 КАК Счетчик ИЗ РегистрСведений.Регистр2) КАК Т
СГРУППИРОВАТЬ ПО
Т.Товар
ИМЕЮЩИЕ
СУММА(Т.Счетчик) <> 0
При работе с большими объемами данных (десятки и сотни тысяч строк) выбор метода становится критичным. Рассмотрим основные правила:
ВТ) перед сравнением, обязательно добавляйте ИНДЕКСИРОВАТЬ ПО ключевому полю (например, Товар). Без индекса соединение таблиц превратится в крайне медленную операцию.ГДЕ Товар НЕ В (ВЫБРАТЬ Товар ИЗ Регистр2) может работать очень медленно на больших массивах данных. Платформа 1С транслирует это в SQL-запрос, который не всегда оптимально обрабатывается сервером базы данных. Соединение (Join) почти всегда работает быстрее.СГРУППИРОВАТЬ ПО или РАЗЛИЧНЫЕ. В противном случае соединения могут привести к "размножению" строк (декартову произведению), что выдаст неверный результат.Товар, а связкой Товар + Характеристика + Склад, не забудьте указать все эти поля в условии связи ПО и проверить каждое на NULL в секции ГДЕ.Рассмотрим пример правильного сравнения по двум полям:
ВЫБРАТЬ
Т1.Товар,
Т1.Характеристика
ИЗ
ВТ_Данные1 КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные2 КАК Т2
ПО Т1.Товар = Т2.Товар
И Т1.Характеристика = Т2.Характеристика
ГДЕ
Т2.Товар ЕСТЬ NULL
Подводя итог, можно сказать, что универсального "лучшего" способа не существует. Для простых задач идеально подходит Способ 1 или Способ 2. Для сложных систем сверки данных, где важна скорость и работа с PostgreSQL, рекомендуем использовать Способ 4 или комбинацию левых соединений. Выбирайте метод исходя из объемов ваших данных и требований к производительности системы.