Как правильно объединять данные в запросе 1С: ПОЛНОЕ СОЕДИНЕНИЕ с ЕСТЬNULL или ОБЪЕДИНИТЬ ВСЕ?

Программист IT и автоматизация бизнеса
← На главную

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

Вариант 1: Использование ПОЛНОГО СОЕДИНЕНИЯ и функции ЕСТЬNULL

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

Пример такого запроса:


ВЫБРАТЬ
	ЕСТЬNULL(Т1.Номенклатура, Т2.Номенклатура) КАК Номенклатура,
	ЕСТЬNULL(Т1.Характеристика, Т2.Характеристика) КАК Характеристика,
	ЕСТЬNULL(Т1.Количество, 0) КАК Количество1,
	ЕСТЬNULL(Т2.Количество, 0) КАК Количество2
ИЗ
	Таблица1 КАК Т1
		ПОЛНОЕ СОЕДИНЕНИЕ Таблица2 КАК Т2
		ПО Т1.Номенклатура = Т2.Номенклатура
			И Т1.Характеристика = Т2.Характеристика

Проанализируем скрытые проблемы и подводные камни этой конструкции:

  1. Ограничения логики сравнения с NULL в условиях соединения: в SQL-логике сравнение NULL = NULL дает результат UNKNOWN (ложь). Если в каком-либо из полей сопоставления (например, характеристика не заполнена и имеет значение NULL) окажется NULL в обоих источниках, строки не соединятся между собой, а продублируются в результирующей выборке как две отдельные записи.
  2. Несовместимость типов в ЕСТЬNULL: функция ЕСТЬNULL обрабатывает исключительно системный тип NULL. Если поля в источниках имеют несовместимые типы данных, результирующая колонка может получить составной тип, что усложнит дальнейшую обработку и выгрузку в таблицу значений. Кроме того, ЕСТЬNULL не заменяет пустые ссылки, пустые строки и нулевые даты.
  3. Проблемы производительности на уровне СУБД: при выполнении ПОЛНОЕ СОЕДИНЕНИЕ оптимизаторы СУБД (особенно PostgreSQL, а также MS SQL Server) не могут эффективно применить технику проброса предикатов (Predicate Pushdown) и использовать быстрые индексные соединения (Index Nested Loops). СУБД вынуждена выполнять тяжелые операции Hash Join или Merge Join, что при больших объемах данных приводит к повышенной нагрузке на память и сбросу промежуточных результатов на диск (в tempdb или временные файлы).

Вариант 2: Использование ОБЪЕДИНИТЬ ВСЕ и СГРУППИРОВАТЬ ПО (Рекомендуемый стандарт)

Стандарты разработки 1С рекомендуют избегать использования полного соединения при сведении и агрегации таблиц. Вместо этого оптимальным паттерном является вертикальное объединение наборов данных через ОБЪЕДИНИТЬ ВСЕ с последующей группировкой.

Разберем по шагам правильный алгоритм построения такого запроса:

  1. В первой ветке запроса выбираем измерения и ресурсы первой таблицы, а ресурсные поля второй таблицы заполняем нулевыми значениями (0).
  2. Во второй ветке запроса через ОБЪЕДИНИТЬ ВСЕ выбираем измерения второй таблицы, нулевые значения для ресурсов первой таблицы и фактические значения ресурсов второй таблицы.
  3. Оборачиваем объединенный набор во вложенный запрос или помещаем во временную таблицу и применяем конструкцию СГРУППИРОВАТЬ ПО со сверткой числовых ресурсов через агрегатную функцию СУММА().

Посмотрим на практический пример реализации:


ВЫБРАТЬ
	ВложенныйЗапрос.Номенклатура КАК Номенклатура,
	ВложенныйЗапрос.Характеристика КАК Характеристика,
	СУММА(ВложенныйЗапрос.Количество1) КАК Количество1,
	СУММА(ВложенныйЗапрос.Количество2) КАК Количество2
ИЗ
	(ВЫБРАТЬ
		Т1.Номенклатура КАК Номенклатура,
		Т1.Характеристика КАК Характеристика,
		Т1.Количество КАК Количество1,
		0 КАК Количество2
	ИЗ
		Таблица1 КАК Т1
	
	ОБЪЕДИНИТЬ ВСЕ
	
	ВЫБРАТЬ
		Т2.Номенклатура КАК Номенклатура,
		Т2.Характеристика КАК Характеристика,
		0 КАК Количество1,
		Т2.Количество КАК Количество2
	ИЗ
		Таблица2 КАК Т2) КАК ВложенныйЗапрос

СГРУППИРОВАТЬ ПО
	ВложенныйЗапрос.Номенклатура,
	ВложенныйЗапрос.Характеристика

Преимущества схемы с ОБЪЕДИНИТЬ ВСЕ

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

  1. Высокая скорость выполнения: операция ОБЪЕДИНИТЬ ВСЕ выполняется СУБД в потоковом режиме без накладных расходов на проверку уникальности строк, после чего последующая группировка по полям отрабатывает значительно быстрее и предсказуемее тяжелого полного соединения.
  2. Корректная обработка пустых значений: при группировке строки с одинаковыми пустыми значениями или NULL корректно сворачиваются в одну итоговую запись, исключая дублирование данных.
  3. Чистота типизации: отпадает необходимость применять громоздкие цепочки из ЕСТЬNULL для каждого измерения, что делает текст запроса более читаемым и снижает вероятность логических ошибок.

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

← На главную