Иногда возникает необходимость убрать дубли из результата запроса. Причём делать это хочется при помощи запроса - так быстрее (критично на больших объёмах данных).
Дубли имеются в виду частичные - т.е. это такие записи, где значения, скажем, по 3 полям совпадают (у двух или более записей), а по остальным полям - нет. Я назвал такие совпадающие поля условно "поля сверки дублей". В общем-то, их может быть сколько угодно - не обязательно именно 3.
Я написал процедуру, убирающую дубли запросом. Она принимает на входе временную таблицу запроса, из которой надо удалить дубли, список полей сверки дублей. Результат помещается в новую временную таблицу того же запроса. Опционально она может показать найденные дубли (и даже вывести их на экран в печатной таблице). Вот код этой процедуры:
Она проверена в 1С:Бухгалтерия 2.5, в ЗУП, возможно, потребуется исправить "ОбщегоНазначения" на "ОбщегоНазначенияЗК".
// Процедура удаления дублей из временной таблице запроса (только для обычных форм).
// Параметры:
// "Запрос" - запрос, содержащий временную таблицу, из которой надо удалить дубли.
// "ИмяВТВход" - имя временной таблицы запроса, из которой надо удалить дубли. Удаляется после проработки процедуры (как более не нужная).
// "ПоляСверкиДубля" - строка вида "Поле1,Поле2,Поле3", содержащая имена тех полей из "ИмяВТВход", по которым мы будем искать дубли.
// "ИмяВТВыход" - имя временной таблицы запроса, в которую помещается результат работы процедуры - т.е. "ИмяВТВход", откуда убрали все дубли.
// "ОставитьВТДубли" - оставить или нет временную таблицу с обнаруженными дублями после проработки процедуры. 
// "ПоказыватьДубли" - выводить или нет печатную таблицу с обнаруженными дублями.
// "ЗаголовокТаблицыДублей" - заголовок для печатной таблицы "ПоказыватьДубли".
Процедура УдалитьДублиВТ(Запрос, ИмяВТВход, ПоляСверкиДубля, ИмяВТВыход, ОставитьВТДубли = Ложь, ПоказыватьДубли = Ложь, ЗаголовокТаблицыДублей = "Таблица найденных дублей")
	//Прототип: http://www.forum.mista.ru/topic.php?id=550537
	
	МПСД = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(ПоляСверкиДубля,",");
	
	ПоляЗапроса = "";
	
	ПоляСоединения = "";
	
	Для каждого Элем Из МПСД Цикл
		
		ПоляЗапроса = ПоляЗапроса + ИмяВТВход + "." + Элем + ", ";
		
		ПоляСоединения = ПоляСоединения + "(" + ИмяВТВход + "." + Элем + " = " + "ВТ_ДУБЛИ1." + Элем + ") И ";
	
	КонецЦикла;
	
	ПоляЗапроса = Лев(ПоляЗапроса, СтрДлина(ПоляЗапроса)-2);
	
	ПоляСоединения = Лев(ПоляСоединения, СтрДлина(ПоляСоединения)-3);
	
	Запрос.Текст = "ВЫБРАТЬ СУММА(1) КАК КоличествоДублей, " + ПоляЗапроса + " ПОМЕСТИТЬ ВТ_ДУБЛИ ИЗ " + ИмяВТВход + " КАК " + ИмяВТВход + 
	" СГРУППИРОВАТЬ ПО " + ПоляЗапроса + " ИМЕЮЩИЕ СУММА(1) > 1 ; ВЫБРАТЬ ВТ_ДУБЛИ.*, 1 КАК СтрокаДубля ПОМЕСТИТЬ ВТ_ДУБЛИ1 ИЗ ВТ_ДУБЛИ КАК ВТ_ДУБЛИ; ";
	
	Запрос.Текст = Запрос.Текст + "ВЫБРАТЬ " + ИмяВТВход + ".*, ЕСТЬNULL(ВТ_ДУБЛИ1.СтрокаДубля,0) КАК СтрокаДубля ПОМЕСТИТЬ ВТ_ВЫХОД ИЗ " + ИмяВТВход + " КАК " + ИмяВТВход +
	" ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ДУБЛИ1 КАК ВТ_ДУБЛИ1 ПО " + ПоляСоединения + " ГДЕ ВТ_ДУБЛИ1.СтрокаДубля ЕСТЬ NULL";
	
	Запрос.Выполнить();
	
	Если ПоказыватьДубли Тогда
		
		ДанныеТаблицы = Новый Запрос;
		ДанныеТаблицы.МенеджерВременныхТаблиц = Запрос.МенеджерВременныхТаблиц;
		ДанныеТаблицы.Текст =
		"Выбрать 0 КАК НомерСтроки, *
		|    Из ВТ_ДУБЛИ
		|";
		
		ТЗДубли = ДанныеТаблицы.Выполнить().Выгрузить();
		
		Для Сч = 0 По ТЗДубли.Количество()-1 Цикл
			
			ТЗДубли[Сч].НомерСтроки = Сч + 1;
		
		КонецЦикла;
		
		Построитель=Новый ПостроительОтчета(); 
		Построитель.ИсточникДанных=Новый ОписаниеИсточникаДанных(ТЗДубли); 
		Построитель.ТекстЗаголовка = ЗаголовокТаблицыДублей;
		Построитель.Вывести();
		
	КонецЕсли; 
	
	ДанныеТаблицы = Новый Запрос;
	ДанныеТаблицы.МенеджерВременныхТаблиц = Запрос.МенеджерВременныхТаблиц;
	ДанныеТаблицы.Текст =
	"Выбрать ПЕРВЫЕ 1 *
	|    Из ВТ_ВЫХОД
	|";
	
	ТЗВыход = ДанныеТаблицы.Выполнить().Выгрузить();	
	
	ПоляЗапроса = "";
	
	Для каждого Колонка Из ТЗВыход.Колонки Цикл
		
		Если Колонка.Имя <> "СтрокаДубля" Тогда
			
			ПоляЗапроса = ПоляЗапроса + Колонка.Имя + ", ";
		
		КонецЕсли;
	
	КонецЦикла; 
	
	ПоляЗапроса = Лев(ПоляЗапроса, СтрДлина(ПоляЗапроса)-2);
	
	Запрос.Текст = "ВЫБРАТЬ " + ПоляЗапроса + " ПОМЕСТИТЬ " + ИмяВТВыход + " ИЗ ВТ_ВЫХОД; УНИЧТОЖИТЬ " + ИмяВТВход + 
	"; УНИЧТОЖИТЬ ВТ_ВЫХОД; УНИЧТОЖИТЬ ВТ_ДУБЛИ1";
	
	Если НЕ ОставитьВТДубли Тогда
		
		Запрос.Текст = Запрос.Текст + "; УНИЧТОЖИТЬ ВТ_ДУБЛИ";
	
	КонецЕсли;
	
	Запрос.Выполнить();	
	
КонецПроцедуры                            Вступайте в нашу телеграмм-группу Инфостарт
