Как убрать задвоение строк в объединяющем запросе 1С

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

При получении остатков товаров по нескольким организациям или разным условиям разработчики часто сталкиваются с проблемой задвоения строк в итоговом результате запроса. Разберем причинно-следственные связи этой ошибки, проанализируем влияние секции ИТОГИ и рассмотрим правильные варианты построения запросов в 1С.

Выясним причину задвоения строк

Часто кажущееся «задвоение» возникнет не из-за ошибки в данных, а из-за специфики работы конструкций языка запросов 1С:

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

Способ 1. Использование временной таблицы и итоговой группировки

Рассмотрим классическое и надежное решение: объединение выборок помещается во временную таблицу, после чего из нее выбираются сгруппированные и просуммированные данные.

Разберем по шагам структуру запроса:

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

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


ВЫБРАТЬ
	ТоварыОрганизацийОстатки.Склад КАК Склад,
	ТоварыОрганизацийОстатки.Номенклатура КАК Номенклатура,
	0 КАК КоличествоОстаток2,
	ТоварыОрганизацийОстатки.КоличествоОстаток КАК КоличествоОстаток1
ПОМЕСТИТЬ ВТ
ИЗ
	РегистрНакопления.ТоварыОрганизаций.Остатки(
		,
		Организация = &Организация
			И Склад = &Склад
			И Номенклатура В ИЕРАРХИИ(&Номенклатура)) КАК ТоварыОрганизацийОстатки

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	ТоварыОрганизацийОстатки.Склад,
	ТоварыОрганизацийОстатки.Номенклатура,
	ТоварыОрганизацийОстатки.КоличествоОстаток,
	0
ИЗ
	РегистрНакопления.ТоварыОрганизаций.Остатки(
		,
		Организация = &Организация2
			И Склад = &Склад
			И Номенклатура В ИЕРАРХИИ(&Номенклатура)) КАК ТоварыОрганизацийОстатки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ВТ.Склад КАК Склад,
	ВТ.Номенклатура КАК Номенклатура,
	СУММА(ВТ.КоличествоОстаток1) КАК КоличествоОстаток1,
	СУММА(ВТ.КоличествоОстаток2) КАК КоличествоОстаток2
ИЗ
	ВТ КАК ВТ
СГРУППИРОВАТЬ ПО
	ВТ.Склад,
	ВТ.Номенклатура

Важное примечание: Перенос фильтров в скобки виртуальной таблицы задействует индексы СУБД, гарантируя максимальное быстродействие при расчете остатков.

Способ 2. Условное суммирование без объединения таблиц

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

Рассмотрим пример реализации:


ВЫБРАТЬ
	ТоварыОрганизацийОстатки.Склад КАК Склад,
	ТоварыОрганизацийОстатки.Номенклатура КАК Номенклатура,
	СУММА(ВЫБОР
		КОГДА ТоварыОрганизацийОстатки.Организация = &Организация
			ТОГДА ТоварыОрганизацийОстатки.КоличествоОстаток
		ИНАЧЕ 0
	КОНЕЦ) КАК КоличествоОстаток1,
	СУММА(ВЫБОР
		КОГДА ТоварыОрганизацийОстатки.Организация = &Организация2
			ТОГДА ТоварыОрганизацийОстатки.КоличествоОстаток
		ИНАЧЕ 0
	КОНЕЦ) КАК КоличествоОстаток2
ИЗ
	РегистрНакопления.ТоварыОрганизаций.Остатки(
		,
		Организация В (&МассивОрганизаций)
			И Склад = &Склад
			И Номенклатура В ИЕРАРХИИ(&Номенклатура)) КАК ТоварыОрганизацийОстатки
СГРУППИРОВАТЬ ПО
	ТоварыОрганизацийОстатки.Склад,
	ТоварыОрганизацийОстатки.Номенклатура

В параметр &МассивОрганизаций передается массив, содержащий Организация1 и Организация2. Этот метод выполняет всего одно обращение к базе данных, исключает операции объединения временных таблиц и автоматически сводит данные в одну строку по каждой номенклатуре.

Правила работы с результатом запроса в коде

Если результат запроса выводится в плоскую табличную часть обработки или форму отчета, соблюдайте следующие правила:

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