//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирКлиент Экспорт;

Перем ПризнакРавно Экспорт; // признаки сравнения
Перем ПризнакНеРавно Экспорт;
Перем ПризнакТолько1 Экспорт;
Перем ПризнакТолько2 Экспорт;
Перем ВыводитьРазницу Экспорт; // флаг, выводить ли разницу числовых сравниваемых колонок
Перем ВсегоРазличий Экспорт; // количество найденных различий при сравнении файлов
Перем ЗагрузкаТабличныхДанных1 Экспорт;
Перем ЗагрузкаТабличныхДанных2 Экспорт;
Перем КонсольЗапросов1 Экспорт;
Перем КонсольЗапросов2 Экспорт;
Перем мИмяГруппыКлючевыхКолонок Экспорт;
Перем мИмяГруппыСравниваемыхКолонок Экспорт;
Перем мИмяГруппыНесравниваемыхКолонок Экспорт;
Перем мИмяГруппыРазностныхКолонок Экспорт;
Перем мИмяКолонкиРезультатаСравнения Экспорт;
Перем мИмяКолонкиНомераСтрокиРезультата Экспорт;
Перем СравниваемыеКолонкиРезультата Экспорт;
Перем СтруктураКолонокРезультата Экспорт;
Перем мИменаВозвращаемыхСвойств Экспорт;
Перем ИмяКолонкиНомерСтроки Экспорт;

Функция ОбновитьДанныеТаблицы(Знач НомерСтороны, Интерактивно = Ложь, СброситьНастройки = Ложь) Экспорт
	
	Если ЭтотОбъект["ТипИсточника" + НомерСтороны] = "ТаблицаЗначений" Тогда
		ИмяФайла = ЭтотОбъект["ИмяФайла" + НомерСтороны];
		Если ЗначениеЗаполнено(ИмяФайла) Тогда
			Файл = Новый Файл(ИмяФайла);
			Таблица =  ирОбщий.ЗагрузитьЗначениеИзФайлаЛкс(Файл.ПолноеИмя, Истина);
			ЭтотОбъект["Таблица" + НомерСтороны] = Таблица;
		КонецЕсли; 
	ИначеЕсли ЭтотОбъект["ТипИсточника" + НомерСтороны] = "ТабличныйДокумент" Тогда
		ИмяФайла = ЭтотОбъект["ИмяФайла" + НомерСтороны];
		ЗагрузкаТабличныхДанных = ЗагрузчикТабличныхДанных(НомерСтороны);
		#Если Сервер И Не Сервер Тогда
			ЗагрузкаТабличныхДанных = Обработки.ирЗагрузкаТабличныхДанных.Создать();
		#КонецЕсли
		ФормаЗагрузки = ЗагрузкаТабличныхДанных.ПолучитьФорму(); // Чтобы создались колонки в реквизитах объекта
		Если ЗначениеЗаполнено(ИмяФайла) Тогда
			Файл = Новый Файл(ИмяФайла);
			ТабличныйДокумент = Новый ТабличныйДокумент;
			ТабличныйДокумент.Прочитать(Файл.ПолноеИмя);
			ЗагрузкаТабличныхДанных.ТабличныйДокумент = ТабличныйДокумент;
		КонецЕсли; 
		ЗагрузкаТабличныхДанных.ТаблицаЗначений = ЭтотОбъект["Таблица" + НомерСтороны];
		НастройкаЗагрузки = Неопределено;
		Если Не СброситьНастройки Тогда
			НастройкаЗагрузки = ЭтотОбъект["НастройкаЗагрузки" + НомерСтороны];
		КонецЕсли; 
		Если НастройкаЗагрузки <> Неопределено Тогда
			ЗагрузкаТабличныхДанных.мЗагрузитьНастройку(НастройкаЗагрузки, Не ЗначениеЗаполнено(ИмяФайла));
		Иначе
			Интерактивно = Истина;
		КонецЕсли; 
		ЗагрузкаТабличныхДанных.ОбновитьКолонкиТаблицыЗначений(НастройкаЗагрузки = Неопределено, Ложь);
		ЗагрузкаТабличныхДанных.ОбновитьСопоставлениеКолонокТЗ();
		ЗагрузкаТабличныхДанных.СопоставлениеКолонокТЗЗаполнить();
		Если Интерактивно Тогда
			ФормаЗагрузки.СинхронизироватьРеквизитыОбъекта(ФормаЗагрузки, Ложь);
			ФормаЗагрузки.РежимРедактора = Истина;
			ФормаЗагрузки.ПараметрТабличныйДокумент = ТабличныйДокумент;
			РезультатФормы = ФормаЗагрузки.ОткрытьМодально();
			Если РезультатФормы = Неопределено Тогда
				Возврат Ложь;
			КонецЕсли;
			ЗагрузкаТабличныхДанных.СохранятьДанныеТД = Не ЗначениеЗаполнено(ИмяФайла);
			ЗагрузкаТабличныхДанных.СохранятьДанныеТЗ = Ложь;
			ЭтотОбъект["НастройкаЗагрузки" + НомерСтороны] = ЗагрузкаТабличныхДанных.мПолучитьНастройку();
		КонецЕсли; 
		ЗагрузкаТабличныхДанных.КонвертироватьДанные();
		Таблица = ЗагрузкаТабличныхДанных.ТаблицаЗначений;
		ЭтотОбъект["Таблица" + НомерСтороны] = Таблица;
	ИначеЕсли ЭтотОбъект["ТипИсточника" + НомерСтороны] = "Запрос" Тогда
		КонсольЗапросов = КонсольЗапросов(НомерСтороны);
		Если Ложь
			Или КонсольЗапросов.ДеревоЗапросов.Строки.Количество() = 0
			Или Интерактивно 
		Тогда
			КонсольЗапросов.мФормаБудетОткрыватьсяПовторно = Истина;
			КонсольЗапросов.мКоллекцияДляЗаполнения = Новый ТаблицаЗначений;
			КонсольЗапросов.ОткрытьМодально();
		КонецЕсли; 
		КонсольЗапросов.ВыполнитьЗапрос();
		Таблица = КонсольЗапросов.ЭлементыФормы.РезультатКоллекция.Значение;
		Таблица = ирОбщий.СузитьТипыКолонокТаблицыБезПотериДанныхЛкс(Таблица,,,, Истина);
		ЭтотОбъект["Таблица" + НомерСтороны] = Таблица;
	КонецЕсли; 
	ОбновитьСопоставлениеКолонок();
	ЗаполнитьСопоставлениеКолонок();
	Таблица = ЭтотОбъект["Таблица" + НомерСтороны];
	Если Таблица.Количество() = 0 Тогда
		ирОбщий.СообщитьЛкс("Таблица " + НомерСтороны + " не содержит данных");
		Возврат Ложь;
	КонецЕсли;
	Возврат Истина;

КонецФункции

Функция ЗагрузчикТабличныхДанных(Знач НомерСтороны) Экспорт 
	
	ЗагрузкаТабличныхДанных = ЭтотОбъект["ЗагрузкаТабличныхДанных" + НомерСтороны];
	Если ЗагрузкаТабличныхДанных = Неопределено Тогда
		ЗагрузкаТабличныхДанных = ирОбщий.СоздатьОбъектПоИмениМетаданныхЛкс("Обработка.ирЗагрузкаТабличныхДанных");
		ЭтотОбъект["ЗагрузкаТабличныхДанных" + НомерСтороны] = ЗагрузкаТабличныхДанных;
	КонецЕсли; 
	Возврат ЗагрузкаТабличныхДанных;

КонецФункции

Функция КонсольЗапросов(Знач НомерСтороны = 1) Экспорт 
	
	КонсольЗапросов = ЭтотОбъект["КонсольЗапросов" + НомерСтороны];
	Если КонсольЗапросов = Неопределено Тогда
		КонсольЗапросов = ирОбщий.СоздатьОбъектПоИмениМетаданныхЛкс("Обработка.ирКонсольЗапросов").ПолучитьФорму();
		ЭтотОбъект["КонсольЗапросов" + НомерСтороны] = КонсольЗапросов;
	КонецЕсли; 
	Возврат КонсольЗапросов;

КонецФункции

Процедура ОбновитьСопоставлениеКолонок() Экспорт 
	
	КопияСопоставления1 = КолонкиТаблица1.Выгрузить();
	КопияСопоставления2 = КолонкиТаблица2.Выгрузить();
	КолонкиТаблица2.Очистить();
	Для Каждого Колонка Из Таблица2.Колонки Цикл
		// Теперь будем переключаться на выполнение на клиенте https://www.hostedredmine.com/issues/956621
		//Если ирОбщий.ОбъектВСтрокуXMLЛкс(Таблица2[0][Колонка.Имя],,, Ложь) = Неопределено Тогда // Вызывало ошибку при пустой таблице
		//	Таблица2.ЗаполнитьЗначения(Неопределено, Колонка.Имя);
		//	ирОбщий.СообщитьЛкс(ирОбщий.СтрШаблонЛкс("Очищена несериализуемая колонка ""%1"" таблицы 2", Колонка.Имя));
		//	Продолжить;
		//КонецЕсли;
		СопоставлениеКолонки = КолонкиТаблица2.Добавить();
		СопоставлениеКолонки.Выводить = Истина;
		СопоставлениеКолонки.ИмяКолонки = Колонка.Имя;
		СтараяСтрока = КопияСопоставления2.Найти(СопоставлениеКолонки.ИмяКолонки, "ИмяКолонки");
		Если СтараяСтрока <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(СопоставлениеКолонки, СтараяСтрока, "Выводить"); 
		КонецЕсли; 
		Если ЗначениеЗаполнено(Колонка.Заголовок) Тогда
			СопоставлениеКолонки.СинонимКолонки = Колонка.Заголовок;
		Иначе
			СопоставлениеКолонки.СинонимКолонки = Колонка.Имя;
		КонецЕсли; 
		СопоставлениеКолонки.ОписаниеТипов = ирОбщий.РасширенноеПредставлениеЛкс(Колонка.ТипЗначения);
	КонецЦикла;
	КолонкиТаблица1.Очистить();
	Для Каждого Колонка Из Таблица1.Колонки Цикл
		// Теперь будем переключаться на выполнение на клиенте https://www.hostedredmine.com/issues/956621
		//Если ирОбщий.ОбъектВСтрокуXMLЛкс(Таблица1[0][Колонка.Имя],,, Ложь) = Неопределено Тогда // Вызывало ошибку при пустой таблице
		//	Таблица1.ЗаполнитьЗначения(Неопределено, Колонка.Имя);
		//	ирОбщий.СообщитьЛкс(ирОбщий.СтрШаблонЛкс("Очищена несериализуемая колонка ""%1"" таблицы 1", Колонка.Имя));
		//	Продолжить;
		//КонецЕсли;
		СопоставлениеКолонки = КолонкиТаблица1.Добавить();
		СопоставлениеКолонки.Выводить = Истина;
		СопоставлениеКолонки.ИмяКолонки = Колонка.Имя;
		СтараяСтрока = КопияСопоставления1.Найти(СопоставлениеКолонки.ИмяКолонки, "ИмяКолонки");
		Если СтараяСтрока <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(СопоставлениеКолонки, СтараяСтрока); 
			Колонка2 = Неопределено;
			Если ЗначениеЗаполнено(СопоставлениеКолонки.ИмяКолонки2) Тогда
				Колонка2 = Таблица2.Колонки.Найти(СопоставлениеКолонки.ИмяКолонки2);
			КонецЕсли; 
			СопоставитьКолонку(СопоставлениеКолонки, Колонка2);
		КонецЕсли; 
		Если ЗначениеЗаполнено(Колонка.Заголовок) Тогда
			СопоставлениеКолонки.СинонимКолонки = Колонка.Заголовок;
		Иначе
			СопоставлениеКолонки.СинонимКолонки = Колонка.Имя;
		КонецЕсли; 
		СопоставлениеКолонки.ОписаниеТипов = ирОбщий.РасширенноеПредставлениеЛкс(Колонка.ТипЗначения);
		СопоставлениеКолонки.Числовая = Колонка.ТипЗначения.СодержитТип(Тип("Число"));
	КонецЦикла; 
	ЭтотОбъект.КоличествоСтрок1 = Таблица1.Количество();
	ЭтотОбъект.КоличествоСтрок2 = Таблица2.Количество();
	ВыявитьНеуникальныеКлючи("1");
	ВыявитьНеуникальныеКлючи("2");
	
КонецПроцедуры

Процедура ЗаполнитьСопоставлениеКолонок(ПоИменам = Ложь) Экспорт
	
	Для Каждого Колонка Из Таблица2.Колонки Цикл
		Если Истина
			И ЗагрузкаТабличныхДанных2 <> Неопределено
			И ирОбщий.СтрокиРавныЛкс(Колонка.Имя, ЗагрузкаТабличныхДанных2.мИмяКолонкиНомерСтроки)
		Тогда
			Продолжить;
		КонецЕсли; 
		ПодобратьСопоставлениеКолонкиПоРавенствуСвойства("ИмяКолонки", Колонка);
		ПодобратьСопоставлениеКолонкиПоРавенствуСвойства("СинонимКолонки", Колонка);
	КонецЦикла;
	
КонецПроцедуры

Процедура ПодобратьСопоставлениеКолонкиПоРавенствуСвойства(Знач ИмяПоляРавенства, Знач Колонка)
	
	СтруктураОтбора = Новый Структура("ИмяКолонки2", "");
	СтрокиСопоставления = КолонкиТаблица1.НайтиСтроки(СтруктураОтбора);
	СтрокаИмен = "";
	Для Каждого СтрокаСопоставления Из СтрокиСопоставления Цикл
		Если Не ирОбщий.ЛиОписанияТиповПересекаютсяЛкс(Колонка, Таблица1.Колонки[СтрокаСопоставления.ИмяКолонки]) Тогда
			Продолжить;
		КонецЕсли; 
		Если ирОбщий.СтрокиРавныЛкс(СтрокаСопоставления[ИмяПоляРавенства], Колонка.Имя) Тогда
			СопоставитьКолонку(СтрокаСопоставления, Колонка);
			Прервать;
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Процедура ПодобратьКлючевыеИСравниваемыеКолонки(Знач КлючевыеКолонки = "", Знач СравниваемыеКолонки = "") Экспорт 
	
	СтрокаКлюча1 = "";
	СтрокаКлюча2 = "";                    
	Уникальность1Достигнута = Ложь;
	Уникальность2Достигнута = Ложь;
	Если ЗначениеЗаполнено(КлючевыеКолонки) Тогда
		Для Каждого ИмяКолонки Из ирОбщий.СтрРазделитьЛкс(КлючевыеКолонки, ",", Истина) Цикл
			СтрокаСопоставления = КолонкиТаблица1.Найти(ИмяКолонки, "ИмяКолонки2");
			Если СтрокаСопоставления = Неопределено Тогда
				Продолжить
			КонецЕсли;
			СтрокаСопоставления.Ключевая = Истина;
			ДобавитьКолонкуВСтрокуКлюча(СтрокаСопоставления.ИмяКолонки, СтрокаКлюча1);
			ДобавитьКолонкуВСтрокуКлюча(СтрокаСопоставления.ИмяКолонки2, СтрокаКлюча2);
		КонецЦикла;
		Если ПроверитьУникальностьКлючаТаблицы(Таблица1, СтрокаКлюча1) Тогда
			Уникальность1Достигнута = Истина;
		КонецЕсли; 
		Если ПроверитьУникальностьКлючаТаблицы(Таблица2, СтрокаКлюча2) Тогда
			Уникальность2Достигнута = Истина;
		КонецЕсли; 
	Иначе
		//Если Таблица1.Количество() > 1 И Таблица2.Количество() > 1 Тогда // https://www.hostedredmine.com/issues/933139
			Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(КолонкиТаблица1.Количество(), "Подбор ключа таблиц");
			КолонкиТаблица1.Сортировать("Числовая");
			Для Каждого СтрокаСопоставления Из КолонкиТаблица1 Цикл
				ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
				Если СтрокаСопоставления.ИмяКолонки2 = "" Тогда
					Продолжить;
				КонецЕсли; 
				ДобавитьКолонкуВСтрокуКлюча(СтрокаСопоставления.ИмяКолонки, СтрокаКлюча1);
				ДобавитьКолонкуВСтрокуКлюча(СтрокаСопоставления.ИмяКолонки2, СтрокаКлюча2);
				СтрокаСопоставления.Ключевая = Истина;
				СтрокаСопоставления.Выводить = Истина;
				Если Не ПроверитьУникальностьКлючаТаблицы(Таблица1, СтрокаКлюча1) Тогда
					Продолжить;
				Иначе
					Уникальность1Достигнута = Истина;
				КонецЕсли; 
				Если Не ПроверитьУникальностьКлючаТаблицы(Таблица2, СтрокаКлюча2) Тогда
					Продолжить;
				Иначе
					Уникальность2Достигнута = Истина;
				КонецЕсли; 
				Прервать;
			КонецЦикла;
			ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
			Если Истина 
				И Не Уникальность1Достигнута
				И Не Уникальность2Достигнута
				И Таблица1.Количество() = Таблица2.Количество()
			Тогда
				ирОбщий.УстановитьСвойствоВКоллекцииЛкс(КолонкиТаблица1, "Ключевая", Ложь);
			КонецЕсли;
		//Иначе
		//	Уникальность1Достигнута = Истина;
		//	Уникальность2Достигнута = Истина;
		//КонецЕсли; 
	КонецЕсли;
	Если Истина
		И Не Уникальность1Достигнута 
		И Таблица1.Количество() > 0
		И ЗначениеЗаполнено(СтрокаКлюча1) 
	Тогда
		ирОбщий.СообщитьЛкс("В таблице 1 имеются неуникальные строки по сопоставленным колонкам (" + СтрокаКлюча1 + ")");
	КонецЕсли; 
	Если Истина
		И Не Уникальность2Достигнута 
		И Таблица2.Количество() > 0
		И ЗначениеЗаполнено(СтрокаКлюча2) 
	Тогда
		ирОбщий.СообщитьЛкс("В таблице 2 имеются неуникальные строки по сопоставленным колонкам (" + СтрокаКлюча2 + ")");
	КонецЕсли;
	Если ЗначениеЗаполнено(СравниваемыеКолонки) Тогда
		Для Каждого ИмяКолонки Из ирОбщий.СтрРазделитьЛкс(СравниваемыеКолонки, ",", Истина) Цикл
			СтрокаСопоставления = КолонкиТаблица1.Найти(ИмяКолонки, "ИмяКолонки2");
			Если СтрокаСопоставления = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			СтрокаСопоставления.Сравнивать = Не СтрокаСопоставления.Ключевая;
		КонецЦикла;
	Иначе
		Для Каждого СтрокаСопоставления Из КолонкиТаблица1 Цикл
			Если СтрокаСопоставления.ИмяКолонки2 = "" Тогда
				Продолжить;
			КонецЕсли; 
			СтрокаСопоставления.Сравнивать = Не СтрокаСопоставления.Ключевая;
		КонецЦикла;
	КонецЕсли;
	ВыявитьНеуникальныеКлючи("1");
	ВыявитьНеуникальныеКлючи("2");
	
КонецПроцедуры

Функция ПроверитьУникальностьКлючаТаблицы(Таблица, СтрокаКлюча)
	
	КопияТаблицы = Таблица.Скопировать(, СтрокаКлюча);
	КопияТаблицы.Свернуть(СтрокаКлюча);
	ТолькоУникальные = КопияТаблицы.Количество() = Таблица.Количество();
	Возврат ТолькоУникальные;

КонецФункции

Функция ВыявитьНеуникальныеКлючи(НомерСтороны, выхСтрокаКлючаИсточника = "") Экспорт 
	
	выхСтрокаКлючаИсточника = "";
	Для Каждого СтрокаСопоставления Из КолонкиТаблица1.НайтиСтроки(Новый Структура("Ключевая", Истина)) Цикл
		Если НомерСтороны = "1" Тогда
			ИмяПоля = СтрокаСопоставления.ИмяКолонки;
		Иначе
			ИмяПоля = СтрокаСопоставления.ИмяКолонки2;
		КонецЕсли; 
		Если выхСтрокаКлючаИсточника <> "" Тогда
			выхСтрокаКлючаИсточника = выхСтрокаКлючаИсточника + ",";
		КонецЕсли; 
		выхСтрокаКлючаИсточника = выхСтрокаКлючаИсточника + ИмяПоля;
	КонецЦикла;
	Если ЗначениеЗаполнено(выхСтрокаКлючаИсточника) Тогда
		НеуникальныеКлючи = ирОбщий.НеуникальныеКлючиТаблицыЛкс(ЭтотОбъект["Таблица" + НомерСтороны], выхСтрокаКлючаИсточника);
	Иначе
		НеуникальныеКлючи = Новый Массив;
	КонецЕсли;
	ЭтотОбъект["КоличествоНеуникальныхКлючей" + НомерСтороны] = НеуникальныеКлючи.Количество();
	Возврат НеуникальныеКлючи;

КонецФункции

Процедура ДобавитьКолонкуВСтрокуКлюча(Знач ИмяДобавляемойКолонки, СтрокаКлюча)
	
	Если СтрокаКлюча <> "" Тогда
		СтрокаКлюча = СтрокаКлюча + ",";
	КонецЕсли; 
	СтрокаКлюча = СтрокаКлюча + ИмяДобавляемойКолонки;

КонецПроцедуры

Процедура СопоставитьКолонку(Знач СтрокаСопоставления, Знач Колонка = Неопределено) Экспорт 
	
	Если Колонка <> Неопределено Тогда
		Для Каждого СтрокаСтарая Из КолонкиТаблица1.НайтиСтроки(Новый Структура("ИмяКолонки2", Колонка.Имя)) Цикл
			Если СтрокаСтарая = СтрокаСопоставления Тогда
				Продолжить;
			КонецЕсли;
			// Если у подходящей колонки таблицы 2 уже есть сопоставление, то делаем ничего
			Возврат;
		КонецЦикла;
		
		СтрокаКолонки2 = КолонкиТаблица2.Найти(Колонка.Имя, "ИмяКолонки");
		Если СтрокаКолонки2 <> Неопределено Тогда
			СтрокаКолонки2.ИмяКолонки1 = СтрокаСопоставления.ИмяКолонки;
			СтрокаКолонки2.СинонимКолонки1 = СтрокаСопоставления.СинонимКолонки;
		КонецЕсли; 
		СтрокаСопоставления.ИмяКолонки2 = Колонка.Имя;
		СтрокаСопоставления.СинонимКолонки2 = Колонка.Заголовок;
		СтрокаСопоставления.ОписаниеТипов2 = ирОбщий.РасширенноеПредставлениеЛкс(Колонка.ТипЗначения);
	Иначе
		СтрокаКолонки2 = КолонкиТаблица2.Найти(СтрокаСопоставления.ИмяКолонки2, "ИмяКолонки");
		Если СтрокаКолонки2 <> Неопределено Тогда
			СтрокаКолонки2.ИмяКолонки1 = "";
			СтрокаКолонки2.СинонимКолонки1 = "";
		КонецЕсли; 
		СтрокаСопоставления.ИмяКолонки2 = "";
		СтрокаСопоставления.СинонимКолонки2 = "";
		СтрокаСопоставления.ОписаниеТипов2 = Неопределено;
		СтрокаСопоставления.Ключевая = Ложь;
		СтрокаСопоставления.Сравнивать = Ложь;
	КонецЕсли; 

КонецПроцедуры

Функция Сравнить2СтрокиПоКолонкам(Знач КолонкиСопоставления, Знач Строка1, Знач Строка2, Знач ТабличныеЧасти1, Знач ТабличныеЧасти2, Знач РазличныеКолонки)
	
	Если ирКэш.РежимОтладкиЛкс() Тогда 
		// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
		Для Каждого СтрокаСопоставления Из КолонкиСопоставления Цикл
			// Мультиметка34ы46754674 Логика скопирована из СравнитьЗначенияЯчеек()
			ЗначенияЯчеекРавны = Истина;
			Если НеУчитыватьРегистр Тогда
				// сравнение без учета регистра имеет смысл только для строк
				ЛевоеЗначение = Строка1[СтрокаСопоставления.ИмяКолонки];
				ПравоеЗначение = Строка2[СтрокаСопоставления.ИмяКолонки2];
				Если ТипЗнч(ЛевоеЗначение) = Тип("Строка") И ТипЗнч(ПравоеЗначение) = Тип("Строка") Тогда
					Если ВРег(ЛевоеЗначение) <> ВРег(ПравоеЗначение) Тогда
						ЗначенияЯчеекРавны = Ложь;
					КонецЕсли;
				Иначе
					Если ЛевоеЗначение <> ПравоеЗначение Тогда
						ЗначенияЯчеекРавны = Ложь;
					КонецЕсли;
				КонецЕсли;
			Иначе
				Если Строка1[СтрокаСопоставления.ИмяКолонки] <> Строка2[СтрокаСопоставления.ИмяКолонки2] Тогда
					ЗначенияЯчеекРавны = Ложь; 
				КонецЕсли; 
			КонецЕсли; 
			Если Не ЗначенияЯчеекРавны Тогда
				РазличныеКолонки.Добавить(СтрокаСопоставления.ИмяКолонки);
			КонецЕсли; 
		КонецЦикла;
	Иначе
		// Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru)
		Для Каждого СтрокаСопоставления Из КолонкиСопоставления Цикл    		ЗначенияЯчеекРавны = Истина;  		Если НеУчитыватьРегистр Тогда    			ЛевоеЗначение = Строка1[СтрокаСопоставления.ИмяКолонки];  			ПравоеЗначение = Строка2[СтрокаСопоставления.ИмяКолонки2];  			Если ТипЗнч(ЛевоеЗначение) = Тип("Строка") И ТипЗнч(ПравоеЗначение) = Тип("Строка") Тогда  				Если ВРег(ЛевоеЗначение) <> ВРег(ПравоеЗначение) Тогда  					ЗначенияЯчеекРавны = Ложь;  				КонецЕсли;  			Иначе  				Если ЛевоеЗначение <> ПравоеЗначение Тогда  					ЗначенияЯчеекРавны = Ложь;  				КонецЕсли;  			КонецЕсли;  		Иначе  			Если Строка1[СтрокаСопоставления.ИмяКолонки] <> Строка2[СтрокаСопоставления.ИмяКолонки2] Тогда  				ЗначенияЯчеекРавны = Ложь;  			КонецЕсли;  		КонецЕсли;  		Если Не ЗначенияЯчеекРавны Тогда  			РазличныеКолонки.Добавить(СтрокаСопоставления.ИмяКолонки);  		КонецЕсли;  	КонецЦикла;  
	КонецЕсли; 
	Для Каждого КлючИЗначение Из ТабличныеЧасти1 Цикл
		ЗначенияЯчеекРавны = Истина;
		Если Не ирОбщий.СериализацииРавныЛкс(КлючИЗначение.Значение, ТабличныеЧасти2[КлючИЗначение.Ключ]) Тогда 
			ЗначенияЯчеекРавны = Ложь; 
		КонецЕсли; 
		Если Не ЗначенияЯчеекРавны Тогда
			РазличныеКолонки.Добавить(КлючИЗначение.Ключ);
		КонецЕсли; 
	КонецЦикла;
	
	//РазличныеКолонки = Новый СписокЗначений;
	//Для Каждого Колонка Из Строка1.Владелец().Колонки Цикл
	//	Если Строка1[Колонка.Имя] <> Строка2[Колонка.Имя] Тогда
	//		РазличныеКолонки.Добавить(Колонка.Имя);
	//	КонецЕсли; 
	//КонецЦикла;
	//Для Каждого КлючИЗначение Из ТабличныеЧасти1 Цикл
	//	Если Не ирОбщий.СериализацииРавныЛкс(КлючИЗначение.Значение, ТабличныеЧасти2[КлючИЗначение.Ключ]) Тогда 
	//		РазличныеКолонки.Добавить("#" + КлючИЗначение.Ключ);
	//	КонецЕсли; 
	//КонецЦикла;
	//РазличныеКолонки.СортироватьПоЗначению();
	//Для Каждого РазличнаяКолонка Из РазличныеКолонки Цикл
	//	Если ТекстРазличий <> "" Тогда
	//		ТекстРазличий = ТекстРазличий + ",";
	//	КонецЕсли; 
	//	ТекстРазличий = ТекстРазличий + РазличнаяКолонка.Значение;
	//КонецЦикла;

	Возврат РазличныеКолонки.Количество() = 0;

КонецФункции

Функция СравнитьЗначенияЯчеек(Знач ЛевоеЗначение, Знач ПравоеЗначение) Экспорт 
	
	// Мультиметка34ы46754674
	ЗначенияЯчеекРавны = Истина;
	Если СравниватьЧерезСериализацию Тогда
		ЛевоеЗначение = ирОбщий.ОбъектВСтрокуДляСравненияВнутрЛкс(ЛевоеЗначение);
		ПравоеЗначение = ирОбщий.ОбъектВСтрокуДляСравненияВнутрЛкс(ПравоеЗначение);
	КонецЕсли;
	// регистронезависимое сравнение
	Если НеУчитыватьРегистр Тогда 
		// сравнение без учета регистра имеет смысл только для строк
		Если ТипЗнч(ЛевоеЗначение) = Тип("Строка") И ТипЗнч(ПравоеЗначение) = Тип("Строка") Тогда
			Если ВРег(ЛевоеЗначение) <> ВРег(ПравоеЗначение) Тогда
				ЗначенияЯчеекРавны = Ложь;
			КонецЕсли;
		Иначе
			Если ЛевоеЗначение <> ПравоеЗначение Тогда
				ЗначенияЯчеекРавны = Ложь;
			КонецЕсли;
		КонецЕсли;
	Иначе	
		// регистрозависимое сравнение
		Если ЛевоеЗначение <> ПравоеЗначение Тогда
			ЗначенияЯчеекРавны = Ложь;
		КонецЕсли;
	КонецЕсли;
	Возврат ЗначенияЯчеекРавны;

КонецФункции

// Результат - Истина, если таблицы равны
Функция СравнитьТаблицы(Параметры) Экспорт 
	
	#Если Сервер И Не Сервер Тогда
		Параметры = Новый Структура
	#КонецЕсли
	РежимСравненияСВыгрузкой = Параметры.РежимСравненияСВыгрузкой;
	Если Истина
		И РежимСравненияСВыгрузкой 
		И Параметры.Свойство("ДанныеФайлов")
	Тогда
		ЭтотОбъект.КаталогВыгрузки = ПолучитьИмяВременногоФайла();
		СоздатьКаталог(КаталогВыгрузки);
		Разделитель = ирОбщий.РазделительПутиКФайлуЛкс();
		Для Каждого КлючИЗначение Из Параметры.ДанныеФайлов Цикл
			КлючИЗначение.Значение.Записать(КаталогВыгрузки + Разделитель + КлючИЗначение.Ключ);
		КонецЦикла; 
	КонецЕсли;
	МетаданныеВыгрузкиЛ = Параметры.МетаданныеВыгрузки;
	КлючевыеКолонки = КолонкиТаблица1.Выгрузить(Новый Структура("Ключевая", Истина));
	ВыводимыеКолонки1 = КолонкиТаблица1.Выгрузить(Новый Структура("Ключевая, Выводить", Ложь, Истина)).ВыгрузитьКолонку("ИмяКолонки");
	ВыводимыеКолонки2 = Новый Массив;
	Для Каждого СтрокаКолонки Из КолонкиТаблица2.НайтиСтроки(Новый Структура("Выводить", Истина)) Цикл
		Если КлючевыеКолонки.Найти(СтрокаКолонки.ИмяКолонки, "ИмяКолонки2") = Неопределено Тогда
			ВыводимыеКолонки2.Добавить(СтрокаКолонки.ИмяКолонки);
		КонецЕсли; 
	КонецЦикла;
	КолонкиРазницыЧисел = КолонкиТаблица1.НайтиСтроки(Новый Структура("Сравнивать, Числовая", Истина, Истина));
	СтрокаПорядка1 = ирОбщий.СтрСоединитьЛкс(КлючевыеКолонки.ВыгрузитьКолонку("ИмяКолонки"));
	СтрокаПорядка2 = ирОбщий.СтрСоединитьЛкс(КлючевыеКолонки.ВыгрузитьКолонку("ИмяКолонки2"));
	ТабличныеЧасти = Новый Структура;
	ТабличныеЧастиЭталона = Новый Структура;
	ТабличныеЧастиСтроки = Новый Структура;
	ТабличныеЧастиСтрокиЭталона = Новый Структура;
	Если РежимСравненияСВыгрузкой Тогда
		СчитанаПоследняяПорция = Ложь;
		СчитанаПоследняяПорцияЭталона = Ложь;
		СтруктураТаблицы = Новый Структура;
		Запрос = ПодготовитьЗапросСравненияВыгрузки(СтруктураТаблицы);
		КоличествоПорцийЭталона = МетаданныеВыгрузкиЛ.КоличествоПорций;
		ОсталосьПорцийЭталона = КоличествоПорцийЭталона;
		РезультатЗапроса = ВыполнитьЗапросСИндикатором(Запрос);
		Если СтруктураТаблицы.ТабличныеЧасти.Количество() > 0 Тогда
			РазмерПорции = 1000;
		Иначе
			РазмерПорции = 100000;
		КонецЕсли; 
		//РазмерПорции = 10; // Для отладки
		НомерПорции = 0;
		Выборка = РезультатЗапроса.Выбрать();
		ТабличныеЧасти = СкопироватьТабличныеЧасти(СтруктураТаблицы.ТабличныеЧасти);
		КолонкиВложенныхТаблиц = Неопределено;
		ВременныйКаталог = ПолучитьИмяВременногоФайла();
		ПорцияОсновнойТаблицы = СоздатьТаблицуПорции(РезультатЗапроса);
		#Если _ Тогда
			ПорцияОсновнойТаблицы = Новый ТаблицаЗначений;
			ТабличныеЧасти = Новый Структура;
		#КонецЕсли
		ПорцияОсновнойТаблицыЭталона = Новый ТаблицаЗначений;
		КоличествоСтрок = Выборка.Количество();
		КоличествоСтрокЭталона = МетаданныеВыгрузкиЛ.КоличествоСтрок;
	Иначе
		СчитанаПоследняяПорция = Истина;
		СчитанаПоследняяПорцияЭталона = Истина;
		ПорцияОсновнойТаблицыЭталона = Таблица1;
		Если ЗначениеЗаполнено(СтрокаПорядка1) Тогда
			ПорцияОсновнойТаблицыЭталона.Сортировать(СтрокаПорядка1, Новый СравнениеЗначений);
		КонецЕсли; 
		ПорцияОсновнойТаблицы = Таблица2;
		Если ЗначениеЗаполнено(СтрокаПорядка2) Тогда
			ПорцияОсновнойТаблицы.Сортировать(СтрокаПорядка2, Новый СравнениеЗначений);
		КонецЕсли; 
		КоличествоСтрок = ПорцияОсновнойТаблицы.Количество();
		КоличествоСтрокЭталона = ПорцияОсновнойТаблицыЭталона.Количество();
	КонецЕсли; 
	ЕстьТЧ = ТабличныеЧасти.Количество() > 0;
	СоздатьКолонкиРезультата();
	КолонкиСопоставления = КолонкиТаблица1.НайтиСтроки(Новый Структура("Сравнивать, Ключевая", Истина, Ложь));
	ВсегоРазличий = 0;
	ИндексСтроки = 0;
	ИндексСтрокиЭталона = 0;
	ВзятьСледующуюСтроку = Истина;
	ВзятьСледующуюСтрокуЭталона = Истина;
	СчитанаПоследняяПорция = Истина;
	СчетчикИзменных = 0;
	СчетчикДобавленных = 0;
	СчетчикУдаленных = 0;
	Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(КоличествоСтрок + КоличествоСтрокЭталона, "Сравнение");
	Пока Истина Цикл
		Если Ложь
			Или ИндексСтроки % 100 = 0
			Или ИндексСтрокиЭталона % 100 = 0
		Тогда
			ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
		КонецЕсли; 
		Если ВзятьСледующуюСтроку Тогда
			Если Не РежимСравненияСВыгрузкой Или ЕстьТЧ Тогда
				Если ИндексСтроки >= ПорцияОсновнойТаблицы.Количество() Тогда
					Если Не СчитанаПоследняяПорция Тогда
						ПорцияОсновнойТаблицы.Очистить();
						Для Каждого КлючИЗначение Из ТабличныеЧасти Цикл
							КлючИЗначение.Значение.Очистить();
						КонецЦикла;
						СчитанаПоследняяПорция = СчитатьПорциюВыборкиВТаблицу(Выборка, ПорцияОсновнойТаблицы, РазмерПорции, ТабличныеЧасти);
						ПодготовитьПорциюТабличныхЧастейКСравнению(ТабличныеЧасти);
						ИндексСтроки = 0;
					КонецЕсли; 
				КонецЕсли; 
				Если ИндексСтроки < ПорцияОсновнойТаблицы.Количество()  Тогда
					ТекущаяСтрока = ПорцияОсновнойТаблицы[ИндексСтроки]; 
				Иначе
					ТекущаяСтрока = Неопределено;
				КонецЕсли; 
			Иначе
				Если Выборка.Следующий() Тогда
					ТекущаяСтрока = Выборка; 
				Иначе
					ТекущаяСтрока = Неопределено;
				КонецЕсли; 
			КонецЕсли; 
			ВзятьСледующуюСтроку = Ложь;
			ИндексСтроки = ИндексСтроки + 1;
		КонецЕсли; 
		Если ВзятьСледующуюСтрокуЭталона Тогда
			Если ИндексСтрокиЭталона >= ПорцияОсновнойТаблицыЭталона.Количество() Тогда
				Если Не СчитанаПоследняяПорцияЭталона Тогда
					НомерПорции = НомерПорции + 1;
					ИмяФайлаПорции = ИмяФайлаПорции(КаталогСравнения, НомерПорции);
					Архив = Новый ЧтениеZipФайла(ИмяФайлаПорции);
					ИмяФайлаДанныхXML = ВременныйКаталог + "\" + Архив.Элементы.Получить(0).Имя;
					Архив.ИзвлечьВсе(ВременныйКаталог);
					ЧтениеXML = Новый ЧтениеXML;
					ЧтениеXML.ОткрытьФайл(ИмяФайлаДанныхXML);
					ЧтениеXML.Прочитать();
					ЧтениеXML.Прочитать();
					ирОбщий.СостояниеЛкс("Десериализация порции");
					СтруктураДанных = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
					ирОбщий.СостояниеЛкс("");
					ПорцияОсновнойТаблицыЭталона = СтруктураДанных.ОсновнаяТаблица;
					ТабличныеЧастиЭталона = СтруктураДанных.ТабличныеЧасти;
					ЧтениеXML.Закрыть();
					ЧтениеXML.Закрыть();
					УдалитьФайлы(ВременныйКаталог);
					ПодготовитьПорциюТабличныхЧастейКСравнению(ТабличныеЧастиЭталона);
					#Если _ Тогда
					    ПорцияОсновнойТаблицыЭталона = Новый ТаблицаЗначений;
					#КонецЕсли
					ИндексСтрокиЭталона = 0;
					ОсталосьПорцийЭталона = ОсталосьПорцийЭталона - 1;
					СчитанаПоследняяПорцияЭталона = ОсталосьПорцийЭталона = 0;
				КонецЕсли; 
			КонецЕсли; 
			Если ИндексСтрокиЭталона < ПорцияОсновнойТаблицыЭталона.Количество()  Тогда
				ТекущаяСтрокаЭталона = ПорцияОсновнойТаблицыЭталона[ИндексСтрокиЭталона]; 
			Иначе
				ТекущаяСтрокаЭталона = Неопределено;
			КонецЕсли; 
			ВзятьСледующуюСтрокуЭталона = Ложь;
			ИндексСтрокиЭталона = ИндексСтрокиЭталона + 1;
		КонецЕсли; 
		Если Истина
			И СчитанаПоследняяПорция
			И ТекущаяСтрока = Неопределено
			И СчитанаПоследняяПорцияЭталона
			И ТекущаяСтрокаЭталона = Неопределено
		Тогда 
			 Прервать;
		 КонецЕсли; 
		СтрокаРезультата = Неопределено;
		РезультатСравненияКлючейСтрок = СравнитьКлючиСтрокТаблиц(ТекущаяСтрокаЭталона, ТекущаяСтрока, КлючевыеКолонки);
		Индикатор.Счетчик = Индикатор.Счетчик + 1;
		Если РезультатСравненияКлючейСтрок = ВидСравнения.Равно Тогда 
			Если ЕстьТЧ Тогда
				ТабличныеЧастиСтроки = Новый Структура;
				Для Каждого КлючИЗначение Из ТабличныеЧасти Цикл
					ТабличныеЧастиСтроки.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение.Скопировать(Новый Структура("Ссылка", ТекущаяСтрока.Ссылка)));
				КонецЦикла;
				ТабличныеЧастиСтрокиЭталона = Новый Структура;
				Для Каждого КлючИЗначение Из ТабличныеЧастиЭталона Цикл
					ТабличныеЧастиСтрокиЭталона.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение.Скопировать(Новый Структура("Ссылка", ТекущаяСтрокаЭталона.Ссылка)));
				КонецЦикла;
			КонецЕсли; 
			РазличныеКолонки = Новый Массив;
			Если Сравнить2СтрокиПоКолонкам(КолонкиСопоставления, ТекущаяСтрокаЭталона, ТекущаяСтрока, ТабличныеЧастиСтрокиЭталона, ТабличныеЧастиСтроки, РазличныеКолонки) Тогда 
				Признак = ПризнакРавно;
			Иначе
				Признак = ПризнакНеРавно;
				СчетчикИзменных = СчетчикИзменных + 1;
			КонецЕсли; 
			Если Признак <> ПризнакРавно Или Не НеВыводитьОдинаковыеСтроки Тогда 
				ВывестиСтрокуРезультата(СтрокаРезультата, ТекущаяСтрокаЭталона, "1", ВыводимыеКолонки1);
				ВывестиСтрокуРезультата(СтрокаРезультата, ТекущаяСтрока, "2", ВыводимыеКолонки2, КлючевыеКолонки);
				Если ВыводитьРазницуЧисловыхКолонокСравнения Тогда
					ВывестиРазницуЧисел(СтрокаРезультата, Признак, КолонкиРазницыЧисел);
				КонецЕсли;
				Для Каждого РазличнаяКолонка Из РазличныеКолонки Цикл
					СтрокаРезультата[РазличнаяКолонка + "Различно"] = Истина;
				КонецЦикла;
			КонецЕсли;
			ВзятьСледующуюСтроку = Истина;
			ВзятьСледующуюСтрокуЭталона = Истина;
			Индикатор.Счетчик = Индикатор.Счетчик + 1;
		ИначеЕсли РезультатСравненияКлючейСтрок = ВидСравнения.Меньше Тогда 
			СчетчикДобавленных = СчетчикДобавленных + 1;
			ВзятьСледующуюСтрокуЭталона = Истина;
			Признак = ПризнакТолько1;
			ВывестиСтрокуРезультата(СтрокаРезультата, ТекущаяСтрокаЭталона, "1", ВыводимыеКолонки1, КлючевыеКолонки);
		ИначеЕсли РезультатСравненияКлючейСтрок = ВидСравнения.Больше Тогда 
			СчетчикУдаленных = СчетчикУдаленных + 1;
			ВзятьСледующуюСтроку = Истина;
			Признак = ПризнакТолько2;
			ВывестиСтрокуРезультата(СтрокаРезультата, ТекущаяСтрока, "2", ВыводимыеКолонки2, КлючевыеКолонки);
		КонецЕсли; 
		Если СтрокаРезультата <> Неопределено Тогда
			СтрокаРезультата[мИмяКолонкиРезультатаСравнения] = Признак;
			Если Признак <> ПризнакРавно Тогда
				ВсегоРазличий = ВсегоРазличий + 1;
			КонецЕсли; 
		КонецЕсли; 
	КонецЦикла; 
	ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
	Если Истина
		И РежимСравненияСВыгрузкой 
		И Параметры.Свойство("ДанныеФайлов")
	Тогда
		УдалитьФайлы(КаталогВыгрузки);
	КонецЕсли; 
	Результат = Новый Структура(мИменаВозвращаемыхСвойств);
	ЗаполнитьЗначенияСвойств(Результат, ЭтотОбъект, мИменаВозвращаемыхСвойств); 
	Результат.Вставить("ЛиТаблицыРавны", ВсегоРазличий = 0);
	Возврат Результат;
	
КонецФункции

Процедура СоздатьКолонкиРезультата(ТабличноеПолеРезультата = Неопределено) Экспорт 
	
	ЭтотОбъект.СравниваемыеКолонкиРезультата = Новый Массив;
	ЭтотОбъект.СтруктураКолонокРезультата = Новый Структура;
	ЭтотОбъект.РезультатСравнения = Новый ТаблицаЗначений;
	РезультатСравнения.Колонки.Добавить(мИмяКолонкиРезультатаСравнения, Новый ОписаниеТипов("Число"), "Результат сравнения");
	РезультатСравнения.Колонки.Добавить(мИмяКолонкиНомераСтрокиРезультата, Новый ОписаниеТипов("Число"));
	КолонкиГруппы = КолонкиТаблица1.НайтиСтроки(Новый Структура("Ключевая", Истина));
	ДобавитьКолонкиТаблицыГруппыРезультата(КолонкиГруппы, "1");
	Если ТабличноеПолеРезультата <> Неопределено Тогда
		ТабличноеПолеРезультата.Колонки.Очистить();
		КолонкаТабличногоПоля = ТабличноеПолеРезультата.Колонки.Добавить(мИмяКолонкиРезультатаСравнения);
		КолонкаТабличногоПоля.Данные = мИмяКолонкиРезультатаСравнения;
		КолонкаТабличногоПоля.ТекстШапки = "Результат сравнения";
		ДобавитьКолонкиТабличногоПоляГруппыРезультата(КолонкиГруппы, мИмяГруппыКлючевыхКолонок, "Ключевые колонки", , "1", "1", ТабличноеПолеРезультата);
	КонецЕсли; 
	СоздатьКолонкиСтороныРезультата("1", ТабличноеПолеРезультата);
	СоздатьКолонкиСтороныРезультата("2", ТабличноеПолеРезультата);
	СоздатьКолонкиРазличий(Новый Структура("Сравнивать", Истина), "Различно", ТабличноеПолеРезультата);
	Если ВыводитьРазницуЧисловыхКолонокСравнения Тогда
		СоздатьКолонкиРазличий(Новый Структура("Числовая, Сравнивать", Истина, Истина), "Разность", ТабличноеПолеРезультата);
	КонецЕсли;
	Если ТабличноеПолеРезультата <> Неопределено Тогда
		//ЭтотОбъект.РезультатСравненияОтобранное = РезультатСравнения;
		ирОбщий.НастроитьДобавленныеКолонкиТабличногоПоляЛкс(ТабличноеПолеРезультата, РезультатСравнения.Колонки,,, Истина);
	КонецЕсли;

КонецПроцедуры

Процедура СоздатьКолонкиРазличий(Знач ОтборКолонок, Знач СуффиксКолонки, Знач ТабличноеПолеРезультата)
	
	КолонкиГруппы = КолонкиТаблица1.НайтиСтроки(ОтборКолонок);
	Для Каждого КолонкаГруппы Из КолонкиГруппы Цикл
		КолонкаИсходнойТаблицы = Таблица1.Колонки[КолонкаГруппы.ИмяКолонки];
		ДобавитьКолонкуТаблицыРезультата(КолонкаГруппы.ИмяКолонки, КолонкаГруппы.ИмяКолонки, КолонкаИсходнойТаблицы, СуффиксКолонки);
	КонецЦикла;
	Если ТабличноеПолеРезультата <> Неопределено Тогда
		ДобавитьКолонкиТабличногоПоляГруппыРезультата(КолонкиГруппы, мИмяГруппыРазностныхКолонок, "Различие колонок", , СуффиксКолонки, "1", ТабличноеПолеРезультата);
	КонецЕсли;

КонецПроцедуры

Функция СравнитьКлючиСтрокТаблиц(Строка1, Строка2, КлючевыеКолонки)
	
	Если Истина
		И Строка1 = Неопределено
		И Строка2 = Неопределено
	Тогда
		Возврат Неопределено;
	ИначеЕсли Истина
		И Строка1 = Неопределено
		И Строка2 <> Неопределено
	Тогда
		Возврат ВидСравнения.Больше;
	ИначеЕсли Истина
		И Строка2 = Неопределено
		И Строка1 <> Неопределено
	Тогда
		Возврат ВидСравнения.Меньше;
	КонецЕсли; 
	СравнениеЗначений = Новый СравнениеЗначений();
	//Если КлючевыеКолонки.Количество() > 0 Тогда
		Результат = ВидСравнения.Равно;
	//Иначе
	//	Результат = ВидСравнения.Больше;
	//КонецЕсли; 
	Если Ложь
		//Или ирКэш.РежимОтладкиЛкс() // Закомментировано для ускорения
	Тогда 
		// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
		Для Каждого СтрокаСравнения Из КлючевыеКолонки Цикл
			РезультатЯчейки = СравнениеЗначений.Сравнить(Строка1[СтрокаСравнения.ИмяКолонки], Строка2[СтрокаСравнения.ИмяКолонки2]);
			Если РезультатЯчейки = 0 Тогда
				//
			ИначеЕсли РезультатЯчейки > 0 Тогда
				Возврат ВидСравнения.Больше;
			Иначе // РезультатЯчейки < 0 Тогда
				Возврат ВидСравнения.Меньше;
			КонецЕсли; 
		КонецЦикла;
	Иначе
		// Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru)
		Для Каждого СтрокаСравнения Из КлючевыеКолонки Цикл  		РезультатЯчейки = СравнениеЗначений.Сравнить(Строка1[СтрокаСравнения.ИмяКолонки], Строка2[СтрокаСравнения.ИмяКолонки2]);  		Если РезультатЯчейки = 0 Тогда    		ИначеЕсли РезультатЯчейки > 0 Тогда  			Возврат ВидСравнения.Больше;  		Иначе  			Возврат ВидСравнения.Меньше;  		КонецЕсли;  	КонецЦикла;  
	КонецЕсли; 
	Возврат Результат;
	
КонецФункции

Процедура СоздатьКолонкиСтороныРезультата(Знач НомерСтороны, Знач ТабличноеПолеРезультата = Неопределено)
	
	// Используем имена сопоставленных колонок от первой стороны
	СопоставленныеНеключевые = КолонкиТаблица1.Выгрузить(Новый Структура("Ключевая, Выводить", Ложь, Истина));
	// Отбросим несопоставленные, т.к. их отдельно выводим
	Отбрасываемые = СопоставленныеНеключевые.НайтиСтроки(Новый Структура("ИмяКолонки2", ""));
	Для Каждого Отбрасываемая Из Отбрасываемые Цикл
		СопоставленныеНеключевые.Удалить(Отбрасываемая);
	КонецЦикла;
	Если НомерСтороны = "1" Тогда
		ИмяКолонкиСопоставления = "ИмяКолонки";
		КорСуффикс = "2"; 
	Иначе
		ИмяКолонкиСопоставления = "ИмяКолонки2";
		КорСуффикс = "1";
	КонецЕсли; 
	ДобавитьКолонкиТаблицыГруппыРезультата(СопоставленныеНеключевые, НомерСтороны, ИмяКолонкиСопоставления);
	КолонкиГруппы = СопоставленныеНеключевые.НайтиСтроки(Новый Структура("Ключевая, Сравнивать", Ложь, Истина));
	Если ТабличноеПолеРезультата <> Неопределено Тогда
		ДобавитьКолонкиТабличногоПоляГруппыРезультата(КолонкиГруппы, мИмяГруппыСравниваемыхКолонок, "Сравниваемые колонки", НомерСтороны, НомерСтороны, НомерСтороны,
			ТабличноеПолеРезультата, ИмяКолонкиСопоставления);
	КонецЕсли; 
	Если НомерСтороны = "1" Тогда
		Для Каждого КолонкаГруппы Из КолонкиГруппы Цикл
			СравниваемыеКолонкиРезультата.Добавить(КолонкаГруппы.ИмяКолонки);
		КонецЦикла;
	КонецЕсли; 
	КолонкиГруппы = СопоставленныеНеключевые.НайтиСтроки(Новый Структура("Выводить, Ключевая, Сравнивать", Истина, Ложь, Ложь));
	Если ТабличноеПолеРезультата <> Неопределено Тогда
		ДобавитьКолонкиТабличногоПоляГруппыРезультата(КолонкиГруппы, мИмяГруппыНесравниваемыхКолонок, "Несравниваемые колонки", НомерСтороны, НомерСтороны, НомерСтороны,
			ТабличноеПолеРезультата, ИмяКолонкиСопоставления,, 5);
	КонецЕсли; 
	// Используем имена несопоставленных колонок от своей стороны
	КолонкиГруппы = ЭтотОбъект["КолонкиТаблица" + НомерСтороны].Выгрузить(Новый Структура("Выводить, ИмяКолонки" + КорСуффикс, Истина, ""));
	ОписаниеКолонкиНомераСтроки = КолонкиГруппы.Вставить(0);
	ОписаниеКолонкиНомераСтроки.Выводить = Истина;
	ОписаниеКолонкиНомераСтроки.ИмяКолонки = ИмяКолонкиНомерСтроки;
	ДобавитьКолонкиТаблицыГруппыРезультата(КолонкиГруппы, НомерСтороны);
	Если ТабличноеПолеРезультата <> Неопределено Тогда
		ДобавитьКолонкиТабличногоПоляГруппыРезультата(КолонкиГруппы, мИмяГруппыНесравниваемыхКолонок, "Несопоставленные колонки", НомерСтороны, НомерСтороны, НомерСтороны,
			ТабличноеПолеРезультата,, Ложь, 5);
	КонецЕсли;

КонецПроцедуры

Функция ДобавитьКолонкиТаблицыГруппыРезультата(Знач КолонкиГруппы, Знач НомерСтороны, ИмяКолонкиСопоставления = "ИмяКолонки")
	
	Массив = Новый Массив;
	Для Каждого КолонкаГруппы Из КолонкиГруппы Цикл
		ИмяКолонки = КолонкаГруппы[ИмяКолонкиСопоставления];
		КолонкаИсходнойТаблицы = ЭтотОбъект["Таблица" + НомерСтороны].Колонки.Найти(ИмяКолонки);
		Если КолонкаИсходнойТаблицы = Неопределено Тогда
			Если ИмяКолонки = ИмяКолонкиНомерСтроки Тогда 
				КолонкаИсходнойТаблицы = Новый Структура("Заголовок, ТипЗначения, Ширина", "№", Новый ОписаниеТипов("Число"), 5);
			Иначе
				ВызватьИсключение ирОбщий.СтрШаблонЛкс("Колонка %1 не найдена", ИмяКолонки);
			КонецЕсли;
		КонецЕсли;
		ИмяКолонкиРезультата = ДобавитьКолонкуТаблицыРезультата(ИмяКолонки, КолонкаГруппы.ИмяКолонки, КолонкаИсходнойТаблицы, НомерСтороны);
		Массив.Добавить(ИмяКолонкиРезультата);
	КонецЦикла;
	Результат = ирОбщий.СтрСоединитьЛкс(Массив);
	Возврат Результат;

КонецФункции

Функция ДобавитьКолонкуТаблицыРезультата(Знач ИмяКолонкиТаблицыРезультата, Знач ИмяИсходнойКолонки, Знач КолонкаИсходнойТаблицы, Суффикс)
	
	ИмяКолонкиРезультата = ИмяКолонкиТаблицыРезультата + Суффикс;
	Если Суффикс = "Различно" Тогда
		ОписаниеТиповКолонки = Новый ОписаниеТипов("Булево");
	Иначе
		КвалификаторыЧисла = КолонкаИсходнойТаблицы.ТипЗначения.КвалификаторыЧисла;
		#Если Сервер И Не Сервер Тогда
		    КвалификаторыЧисла = Новый КвалификаторыЧисла;
		#КонецЕсли
		ОписаниеТиповКолонки = Новый ОписаниеТипов(КолонкаИсходнойТаблицы.ТипЗначения,,,
			Новый КвалификаторыЧисла(КвалификаторыЧисла.Разрядность, КвалификаторыЧисла.РазрядностьДробнойЧасти, ДопустимыйЗнак.Любой));
	КонецЕсли; 
	РезультатСравнения.Колонки.Добавить(ИмяКолонкиРезультата, ОписаниеТиповКолонки, КолонкаИсходнойТаблицы.Заголовок + " " + Суффикс, КолонкаИсходнойТаблицы.Ширина);
	СтруктураКолонокРезультата.Вставить(ИмяКолонкиРезультата, ИмяИсходнойКолонки);
	Возврат ИмяКолонкиРезультата;

КонецФункции

Процедура ДобавитьКолонкиТабличногоПоляГруппыРезультата(Знач КолонкиГруппы, Знач ИмяГруппы, Знач ЗаголовокГруппы, Знач НомерСтороныГруппы = "", СуффиксКолонки = "",
	Знач НомерСтороныКолонки = "", Знач ТабличноеПолеРезультата, ИмяКолонкиСопоставления = "ИмяКолонки", Сопоставленные = Истина, Знач ШиринаГруппы = 0)
	
	#Если Клиент Тогда
		
	Если КолонкиГруппы.Количество() = 0 Тогда
		Возврат;
	КонецЕсли; 
	ЭтоПерваяКолонка = Ложь;
	Если Не РасполагатьСравниваемыеЯчейкиВертикально Тогда
		ИмяКолонкиГруппы = ИмяГруппы + НомерСтороныГруппы;
		КолонкаТабличногоПоля = ТабличноеПолеРезультата.Колонки.Найти(ИмяКолонкиГруппы);
		Если КолонкаТабличногоПоля = Неопределено Тогда
			КолонкаТабличногоПоля = ТабличноеПолеРезультата.Колонки.Добавить(ИмяКолонкиГруппы);
			Если ЗначениеЗаполнено(НомерСтороныГруппы) Тогда
				ЗаголовокГруппы = ЗаголовокГруппы + " " + НомерСтороныГруппы;
			КонецЕсли; 
			КолонкаТабличногоПоля.ТекстШапки = ЗаголовокГруппы;
			КолонкаТабличногоПоля.Ширина = ШиринаГруппы;
			ЭтоПерваяКолонка = Истина;
		КонецЕсли; 
	КонецЕсли; 
	СуффиксКолонкиВнутр = СуффиксКолонки;
	Для Каждого КолонкаГруппы Из КолонкиГруппы Цикл
		ИмяКолонкиИсточника = КолонкаГруппы[ИмяКолонкиСопоставления];
		ИмяКолонкиТаблицыРезультата = ИмяКолонкиИсточника + СуффиксКолонкиВнутр;
		КолонкаТабличногоПоля = ТабличноеПолеРезультата.Колонки.Добавить(ИмяКолонкиТаблицыРезультата);
		КолонкаТабличногоПоля.Данные = ИмяКолонкиТаблицыРезультата;
		СтрокаСинонима = ЭтотОбъект["КолонкиТаблица" + НомерСтороныКолонки].Найти(ИмяКолонкиИсточника, "ИмяКолонки");
		Если СтрокаСинонима = Неопределено Тогда   
			Если ИмяКолонкиИсточника = ИмяКолонкиНомерСтроки Тогда
				СтрокаСинонима = Новый Структура("СинонимКолонки", "№");
			Иначе
				ВызватьИсключение ирОбщий.СтрШаблонЛкс("Колонка %1 не найдена", ИмяКолонкиИсточника);
			КонецЕсли;
		КонецЕсли;
		КолонкаТабличногоПоля.ТекстШапки = СтрокаСинонима.СинонимКолонки;
		КолонкаТабличногоПоля.ПодсказкаВШапке = КолонкаТабличногоПоля.ТекстШапки + " " + СуффиксКолонки;
		Если РасполагатьСравниваемыеЯчейкиВертикально Тогда
			Если Ложь
				Или Не Сопоставленные
				Или СуффиксКолонки = "1" 
			Тогда
				КолонкаТабличногоПоля.Положение = ПоложениеКолонки.НоваяКолонка;
				КолонкаТабличногоПоля.ТекстШапки = КолонкаТабличногоПоля.ТекстШапки + " " + СуффиксКолонки;
				КолонкаТабличногоПоля.ПодсказкаВШапке = ""; // Совпадает с заголовком
			ИначеЕсли Ложь
				Или СуффиксКолонки = "2" 
				Или СуффиксКолонки = "Различно"
				Или СуффиксКолонки = "Разность" 
			Тогда
				Если СуффиксКолонки = "Различно" Тогда
					ИмяПривязкиПоложения = "ИмяКолонки2";
				Иначе
					ИмяПривязкиПоложения = "ИмяКолонки";
				КонецЕсли; 
				Если СуффиксКолонки = "2" Тогда
					СуффиксПарнойКолонки = "1";
				ИначеЕсли СуффиксКолонки = "Разность" Тогда 
					СуффиксПарнойКолонки = "Различно";
				Иначе
					СуффиксПарнойКолонки = "2";
				КонецЕсли;
				КолонкаТабличногоПоля.ТекстШапки = СуффиксКолонки;
				УстановитьПоложениеКолонкиТП(КолонкаГруппы, КолонкаТабличногоПоля, СуффиксКолонки, СуффиксПарнойКолонки, ТабличноеПолеРезультата, ИмяПривязкиПоложения);
			КонецЕсли; 
		Иначе
			Если СуффиксКолонки = "Разность" Тогда
				КолонкаТабличногоПоля.ТекстШапки = "<" + СуффиксКолонки + ">";
				УстановитьПоложениеКолонкиТП(КолонкаГруппы, КолонкаТабличногоПоля, СуффиксКолонки, "Различно", ТабличноеПолеРезультата);
			КонецЕсли; 
			Если ЭтоПерваяКолонка Тогда
				КолонкаТабличногоПоля.Положение = ПоложениеКолонки.НаСледующейСтроке;
				ЭтоПерваяКолонка = Ложь;
			Иначе
				КолонкаТабличногоПоля.Положение = ПоложениеКолонки.ВТойЖеКолонке;
			КонецЕсли; 
		КонецЕсли; 
	КонецЦикла;
	
	#КонецЕсли

КонецПроцедуры

#Если Клиент Тогда

Процедура УстановитьПоложениеКолонкиТП(Знач КолонкаГруппы, КолонкаТабличногоПоля, Знач СуффиксКолонки, Знач СуффиксПарнойКолонки, Знач ТабличноеПолеРезультата, Знач ИмяПривязкиПоложения = "ИмяКолонки")
	
	ПарнаяКолонка = ТабличноеПолеРезультата.Колонки.Найти(КолонкаГруппы[ИмяПривязкиПоложения] + СуффиксПарнойКолонки);
	Если ПарнаяКолонка <> Неопределено Тогда
		ИндексПарнойКолонки = ТабличноеПолеРезультата.Колонки.Индекс(КолонкаТабличногоПоля);
		ТабличноеПолеРезультата.Колонки.Сдвинуть(КолонкаТабличногоПоля, ТабличноеПолеРезультата.Колонки.Индекс(ПарнаяКолонка) - ИндексПарнойКолонки + 1);
		Если СуффиксКолонки = "Разность" Тогда
			КолонкаТабличногоПоля.Положение = ПоложениеКолонки.ВТойЖеКолонке;
		Иначе
			КолонкаТабличногоПоля.Положение = ПоложениеКолонки.НаСледующейСтроке;
		КонецЕсли; 
	КонецЕсли;

КонецПроцедуры

#КонецЕсли

Процедура ВывестиСтрокуРезультата(выхСтрокаРезультата, Знач СтрокаТаблицы, Знач НомерСтороны, Знач ВыводимыеКолонки, Знач КлючевыеКолонки = Неопределено)
	
	#Если Сервер И Не Сервер Тогда
	    СтрокаТаблицы = Новый ТаблицаЗначений;
		СтрокаТаблицы = СтрокаТаблицы.Добавить();
	#КонецЕсли
	Если выхСтрокаРезультата = Неопределено Тогда
		выхСтрокаРезультата = РезультатСравнения.Добавить();
		выхСтрокаРезультата[мИмяКолонкиНомераСтрокиРезультата] = РезультатСравнения.Количество();
	КонецЕсли; 
	_РежимОтладки = Ложь; // ирКэш.РежимОтладкиЛкс() не используем для ускорения
	Если _РежимОтладки Тогда // Можно менять на Истина в точке останова, например условием ирОбщий.Пр(_РежимОтладки, 1, 1)
		// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
		Если КлючевыеКолонки <> Неопределено Тогда
			Если НомерСтороны = "1" Тогда
				Для Каждого КлючеваяКолонка Из КлючевыеКолонки Цикл
					выхСтрокаРезультата[КлючеваяКолонка.ИмяКолонки + "1"] = СтрокаТаблицы[КлючеваяКолонка.ИмяКолонки];
				КонецЦикла;
			Иначе
				Для Каждого КлючеваяКолонка Из КлючевыеКолонки Цикл
					выхСтрокаРезультата[КлючеваяКолонка.ИмяКолонки + "1"] = СтрокаТаблицы[КлючеваяКолонка.ИмяКолонки2];
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
		Для Каждого ИмяКолонки Из ВыводимыеКолонки Цикл
			выхСтрокаРезультата[ИмяКолонки + НомерСтороны] = СтрокаТаблицы[ИмяКолонки];
		КонецЦикла;
		выхСтрокаРезультата[ИмяКолонкиНомерСтроки + НомерСтороны] = СтрокаТаблицы.Владелец().Индекс(СтрокаТаблицы) + 1;
	Иначе
		// Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru)
		Если КлючевыеКолонки <> Неопределено Тогда  			Если НомерСтороны = "1" Тогда  				Для Каждого КлючеваяКолонка Из КлючевыеКолонки Цикл  					выхСтрокаРезультата[КлючеваяКолонка.ИмяКолонки + "1"] = СтрокаТаблицы[КлючеваяКолонка.ИмяКолонки];  				КонецЦикла;  			Иначе  				Для Каждого КлючеваяКолонка Из КлючевыеКолонки Цикл  					выхСтрокаРезультата[КлючеваяКолонка.ИмяКолонки + "1"] = СтрокаТаблицы[КлючеваяКолонка.ИмяКолонки2];  				КонецЦикла;  			КонецЕсли;  		КонецЕсли;  		Для Каждого ИмяКолонки Из ВыводимыеКолонки Цикл  			выхСтрокаРезультата[ИмяКолонки + НомерСтороны] = СтрокаТаблицы[ИмяКолонки];  		КонецЦикла;  		выхСтрокаРезультата[ИмяКолонкиНомерСтроки + НомерСтороны] = СтрокаТаблицы.Владелец().Индекс(СтрокаТаблицы) + 1;  
	КонецЕсли;
КонецПроцедуры

Процедура ЗаписатьСоотвествиеПространствИмен(Знач ЗаписьXML) Экспорт 
	
	#Если Сервер И Не Сервер Тогда
	    ЗаписьXML = Новый ЗаписьXML;
	#КонецЕсли
	ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xs", "http://www.w3.org/2001/XMLSchema");
	ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xi", "http://www.w3.org/2001/XMLSchema-instance");
	ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("v8", "http://v8.1c.ru/data");
	ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("cc", "http://v8.1c.ru/8.1/data/enterprise/current-config");
	
КонецПроцедуры

// Если в описании типов есть более одного ссылочного типа, то они заменяются на ЛюбаяСсылка
Функция КомпактноеОписаниеТиповДляСериализации(ОписаниеТипов) Экспорт 
	
	Результат = ОписаниеТипов;
	Типы = Результат.Типы();
	Если Типы.Количество() > 1 Тогда
		ПримитивныеТипы = Новый Массив;
		Для Каждого Тип Из Типы Цикл
			Если Найти(XMLТип(Тип).ИмяТипа, "Ref.") > 0 Тогда
				Продолжить;
			КонецЕсли; 
			ПримитивныеТипы.Добавить(Тип);
		КонецЦикла;
		ВычитаемыеТипы = Новый Массив;
		//Если УдалятьТипNull Тогда // Удаление типа Null из описания типов колонки уменьшает объем ее xml данных, если в ней остается только один тип. Не рекомендуется включать для данных, полученных из регистра бухгалтерии.
		//	ВычитаемыеТипы.Добавить(Тип("Null"));
		//КонецЕсли; 
		Если Типы.Количество() > ПримитивныеТипы.Количество() + 1 Тогда
			БазовоеОписаниеТипов = ирОбщий.ОписаниеТиповВсеСсылкиЛкс(Ложь);
		Иначе
			БазовоеОписаниеТипов = Результат;
		КонецЕсли; 
		Результат = Новый ОписаниеТипов(БазовоеОписаниеТипов, ПримитивныеТипы, ВычитаемыеТипы, Результат.КвалификаторыЧисла, Результат.КвалификаторыСтроки,
			Результат.КвалификаторыДаты);
	КонецЕсли;
	Возврат Результат;

КонецФункции

// Результат - Булево - Считана последняя порция
Функция СчитатьПорциюВыборкиВТаблицу(Выборка, ТаблицаПриемник, Знач РазмерПорции = 9999, ОбщиеВложенныеТаблицы = Неопределено) Экспорт

	#Если _ Тогда
	    Пустышка = Новый Запрос;
		Выборка = Пустышка.Выполнить();
		ТаблицаПриемник = Новый ТаблицаЗначений;
	#КонецЕсли
	КолонкиВложенныхТаблиц = Новый Массив();
	Для Каждого Колонка Из Выборка.Владелец().Колонки Цикл
		Если Колонка.ТипЗначения.СодержитТип(Тип("РезультатЗапроса")) Тогда
			КолонкиВложенныхТаблиц.Добавить(Колонка.Имя);
		КонецЕсли; 
	КонецЦикла;
	ЕстьКолонкиВложенныхТаблиц = КолонкиВложенныхТаблиц.Количество() > 0;
	РазмерПорцииОсталось = РазмерПорции;
	РедкостьИндикатора = 100;
	Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(РазмерПорции / РедкостьИндикатора, "Чтение порции");
	Результат = Истина;
	Пока Выборка.Следующий() Цикл
		НоваяСтрока = ТаблицаПриемник.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
		Если ЕстьКолонкиВложенныхТаблиц Тогда
			Для Каждого ИмяКолонкиВложеннойТаблицы Из КолонкиВложенныхТаблиц Цикл
				Если ОбщиеВложенныеТаблицы = Неопределено Тогда
					НоваяСтрока[ИмяКолонкиВложеннойТаблицы] = Выборка[ИмяКолонкиВложеннойТаблицы].Выгрузить();
				Иначе
					ТабличнаяЧастьИсточник = Выборка[ИмяКолонкиВложеннойТаблицы].Выгрузить();
					ТабличнаяЧастьПриемник = ОбщиеВложенныеТаблицы[ИмяКолонкиВложеннойТаблицы];
					Если ТабличнаяЧастьПриемник = Неопределено Или ТабличнаяЧастьПриемник.Колонки.Количество() = 0 Тогда
						ТабличнаяЧастьПриемник = ТабличнаяЧастьИсточник;
					Иначе
						ирОбщий.ЗагрузитьВТаблицуЗначенийЛкс(ТабличнаяЧастьИсточник, ТабличнаяЧастьПриемник, Новый Структура("Ссылка", Выборка.Ссылка));
					КонецЕсли; 
				КонецЕсли; 
			КонецЦикла; 
		КонецЕсли; 
		РазмерПорцииОсталось = РазмерПорцииОсталось - 1;
		Если РазмерПорцииОсталось <= 0 Тогда
			Результат = Ложь;
			Прервать;
		КонецЕсли; 
		Если РазмерПорцииОсталось % РедкостьИндикатора = 0 Тогда
			ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
		КонецЕсли; 
	КонецЦикла;
	ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
	Возврат Результат;

КонецФункции

Функция ВыгрузитьДанныеДляСравнения(Параметры = Неопределено) Экспорт
	
	#Если Не Клиент Тогда
		ЭтотОбъект.КаталогВыгрузки = ПолучитьИмяВременногоФайла();
		СоздатьКаталог(КаталогВыгрузки);
	#КонецЕсли
	ЛиСквознаяФайловаяСистема = Параметры.ЛиСквознаяФайловаяСистема;
	УдалитьФайлы(КаталогВыгрузки, МаркерИмениФайлаПорции() + "*.*");
	СтруктураТаблицы = Новый Структура;
	ЗапросДетальный = ПодготовитьЗапросСравненияВыгрузки(СтруктураТаблицы);
	РезультатЗапроса = ВыполнитьЗапросСИндикатором(ЗапросДетальный);
	ТабличныеЧасти = СтруктураТаблицы.ТабличныеЧасти;
	ПорцияОсновнойТаблицы = СоздатьТаблицуПорции(РезультатЗапроса);
	Если ТабличныеЧасти.Количество() > 0 Тогда
		РазмерПорции = 1000;
	Иначе
		РазмерПорции = 100000;
	КонецЕсли; 
	//РазмерПорции = 10; // Для отладки
	Выборка = РезультатЗапроса.Выбрать();
	КоличествоСтрок = Выборка.Количество();
	КоличествоПорций = Цел(КоличествоСтрок / РазмерПорции) + 1;
	
	МетаданныеВыгрузки = Новый Структура;
	МетаданныеВыгрузки.Вставить("КолонкиТаблица1", КолонкиТаблица1.Выгрузить());
	МетаданныеВыгрузки.Вставить("Таблица1", Таблица1.СкопироватьКолонки());
	МетаданныеВыгрузки.Вставить("ЗапросВыгрузки", ЗапросВыгрузки);
	МетаданныеВыгрузки.Вставить("КоличествоСтрок", КоличествоСтрок);
	МетаданныеВыгрузки.Вставить("РазмерПорции", РазмерПорции);
	МетаданныеВыгрузки.Вставить("КоличествоПорций", КоличествоПорций);
	
	СчитанаПоследняяПорция = Ложь;
	НомерПорции = 1;
	Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(КоличествоПорций, "Выгрузка порций");
	Пока Не СчитанаПоследняяПорция Цикл
		ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
		ЗаписьXML = Новый ЗаписьXML;
		ИмяФайлаДанныхXML = ПолучитьИмяВременногоФайла("xml"); 
		ЗаписьXML.ОткрытьФайл(ИмяФайлаДанныхXML);
		Попытка
			ЗаписьXML.ЗаписатьНачалоЭлемента("Порция");
			ЗаписатьСоотвествиеПространствИмен(ЗаписьXML);
			СчитанаПоследняяПорция = СчитатьПорциюВыборкиВТаблицу(Выборка, ПорцияОсновнойТаблицы, РазмерПорции, ТабличныеЧасти);
			Для Каждого КлючИЗначение Из ТабличныеЧасти Цикл
				//ТабличныеЧасти[КлючИЗначение.Ключ] = мСервисныйПроцессор.ПолучитьТаблицуСМинимальнымиТипамиКолонокИис(КлючИЗначение.Значение);
				ТабличныеЧасти[КлючИЗначение.Ключ] = КлючИЗначение.Значение;
			КонецЦикла;
			СтруктураДляЗаписи = Новый Структура;
			СтруктураДляЗаписи.Вставить("ОсновнаяТаблица", ПорцияОсновнойТаблицы);
			СтруктураДляЗаписи.Вставить("ТабличныеЧасти", ТабличныеЧасти);
			СериализаторXDTO.ЗаписатьXML(ЗаписьXML, СтруктураДляЗаписи);
			ПорцияОсновнойТаблицы.Очистить();
			Для Каждого КлючИЗначение Из ТабличныеЧасти Цикл
				КлючИЗначение.Значение.Очистить();
			КонецЦикла;
			ЗаписьXML.ЗаписатьКонецЭлемента();
		Исключение
			ЗаписьXML.Закрыть();
			УдалитьФайлы(ИмяФайлаДанныхXML);
			ВызватьИсключение;
		КонецПопытки; 
		ЗаписьXML.Закрыть();
		ИмяФайлаПорции = ИмяФайлаПорции(КаталогВыгрузки, НомерПорции);
		Архив = Новый ЗаписьZipФайла(ИмяФайлаПорции);
		Архив.Добавить(ИмяФайлаДанныхXML);
		Архив.Записать();
		УдалитьФайлы(ИмяФайлаДанныхXML);
		НомерПорции = НомерПорции + 1;
	КонецЦикла; 
	ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
	Результат = Новый Структура();
	Результат.Вставить("МетаданныеВыгрузки", МетаданныеВыгрузки);
	Если Не ЛиСквознаяФайловаяСистема Тогда 
		Файлы = НайтиФайлы(КаталогВыгрузки, МаркерИмениФайлаПорции() + "*.*");
		ДанныеФайлов = Новый Соответствие;
		Для Каждого Файл Из Файлы Цикл
			#Если Сервер И Не Сервер Тогда
				Файл = Новый Файл;
			#КонецЕсли
			ДанныеФайлов[Файл.Имя] = Новый ДвоичныеДанные(Файл.ПолноеИмя);
		КонецЦикла;
		Результат.Вставить("ДанныеФайлов", ДанныеФайлов);
		УдалитьФайлы(КаталогВыгрузки, МаркерИмениФайлаПорции() + "*.*");
	КонецЕсли;
	Возврат Результат;

КонецФункции

Функция ИмяФайлаМетаданныхСравнения(Знач БазовыйКаталог = "") Экспорт 
	
	Если Не ЗначениеЗаполнено(БазовыйКаталог) Тогда
		БазовыйКаталог = КаталогВыгрузки;
	КонецЕсли;
	ИмяФайлаМетаданных = БазовыйКаталог + "\" + "МетаданныеСравнения.xml";
	Возврат ИмяФайлаМетаданных;

КонецФункции

Функция ВыполнитьЗапросСИндикатором(Знач ЗапросДетальный)
	
	ирОбщий.СостояниеЛкс("Выполнение запроса");
	РезультатЗапроса = ЗапросДетальный.Выполнить();
	ирОбщий.СостояниеЛкс("");
	Возврат РезультатЗапроса;

КонецФункции

Функция СоздатьТаблицуПорции(Знач РезультатЗапроса, Знач ЭтоСсылочныйТип = Ложь)
	
	ПорцияОсновнойТаблицы = Новый ТаблицаЗначений();
	Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл
		Если Ложь
			Или (Истина
				И ЭтоСсылочныйТип
				И Колонка.Имя = "ВерсияДанных")
			Или Колонка.ТипЗначения.СодержитТип(Тип("РезультатЗапроса")) // Этот тип всегда один в описании типов колонки результата
			Или Колонка.ТипЗначения.СодержитТип(Тип("МоментВремени")) // Этот тип всегда один в описании типов колонки результата
			//Или ИсключаемыеПоля.Найти(Колонка.Имя) <> Неопределено
		Тогда
			Продолжить;
		КонецЕсли; 
		ОписаниеТипов = Колонка.ТипЗначения;
		ОписаниеТипов = КомпактноеОписаниеТиповДляСериализации(ОписаниеТипов);
		ПорцияОсновнойТаблицы.Колонки.Добавить(Колонка.Имя, ОписаниеТипов);
	КонецЦикла;
	Возврат ПорцияОсновнойТаблицы;

КонецФункции

Функция ИмяФайлаПорции(Знач БазовыйКаталог, Знач НомерПорции)
	
	ИмяФайлаПорции = КаталогВыгрузки + "\" + МаркерИмениФайлаПорции() + XMLСтрока(НомерПорции) + ".zip";
	Возврат ИмяФайлаПорции;

КонецФункции

Функция МаркерИмениФайлаПорции() Экспорт 
	
	Возврат "ПорцияСравнения";

КонецФункции

Функция ПодготовитьЗапросСравненияВыгрузки(выхСтруктураТаблицы = Неопределено)
	
	СтруктураКлюча = Новый СписокЗначений;
	Для Каждого СтрокаПоля Из КолонкиТаблица1.НайтиСтроки(Новый Структура("Ключевая", Истина)) Цикл
		СтруктураКлюча.Добавить(, СтрокаПоля.ИмяКолонки);
	КонецЦикла; 
	Запрос = Новый Запрос;
	Запрос.Текст = ЗапросВыгрузки.ТекстЗапроса;
	Для Каждого СтрокаПараметра Из ЗапросВыгрузки.Параметры Цикл
		Запрос.Параметры.Вставить(СтрокаПараметра.ИмяПараметра, СтрокаПараметра.Значение);
	КонецЦикла;
	Построитель = Новый ПостроительЗапроса;
	Построитель.Текст = Запрос.Текст;
	Построитель.ЗаполнитьНастройки();
	Построитель.Порядок.Очистить();
	Для Каждого СтрокаПоля Из КолонкиТаблица1.НайтиСтроки(Новый Структура("Ключевая", Истина)) Цикл
		Построитель.Порядок.Добавить(СтрокаПоля.ИмяКолонки);
	КонецЦикла;
	ЗапросДетальныйСПорядком = Построитель.ПолучитьЗапрос();
	Запрос.Текст = ЗапросДетальныйСПорядком.Текст;
	ТабличныеЧасти = Новый Структура;
	ШаблонОсновнойТаблицы = КолонкиРезультатаЗапроса(Запрос.Текст, Ложь, Истина);
	Для Каждого КолонкаШаблона Из ШаблонОсновнойТаблицы.Колонки Цикл
		Если КолонкаШаблона.ТипЗначения.СодержитТип(Тип("ТаблицаЗначений")) Тогда
			Если Не ТабличныеЧасти.Свойство(КолонкаШаблона.Имя) Тогда
				// Предопределенная табличная часть
				ТабличныеЧасти.Вставить(КолонкаШаблона.Имя, Новый ТаблицаЗначений);
			КонецЕсли; 
		КонецЕсли; 
	КонецЦикла;
	выхСтруктураТаблицы = Новый Структура;
	выхСтруктураТаблицы.Вставить("ОсновнаяТаблица", ШаблонОсновнойТаблицы);
	выхСтруктураТаблицы.Вставить("ТабличныеЧасти", ТабличныеЧасти);
	выхСтруктураТаблицы.Вставить("Ключ", СтруктураКлюча);
	Возврат Запрос;

КонецФункции

Функция КолонкиРезультатаЗапроса(ТекстЗапроса, ВключаяЗаголовоки = Истина, КомпактноеОписаниеТипов = Ложь, ИсключаемыеПоля = Неопределено) Экспорт 
	
	ПостроительЗапроса = Новый ПостроительЗапроса;
	Попытка
		ПостроительЗапроса.Текст = ТекстЗапроса;
	Исключение
		ирОбщий.СообщитьЛкс("Ошибка при вычислении колонок результата запроса: " + ОписаниеОшибки());
		Возврат Неопределено;
	КонецПопытки;
	ПостроительЗапроса.ЗаполнитьНастройки();
	Результат = Новый ТаблицаЗначений;
	Для Каждого ОписаниеПоля Из ПостроительЗапроса.ДоступныеПоля Цикл
		Если Истина
			И ИсключаемыеПоля <> Неопределено
			И ИсключаемыеПоля.Найти(ОписаниеПоля.Имя) <> Неопределено
		Тогда
			Продолжить;
		КонецЕсли; 
		НоваяКолонка = Результат.Колонки.Добавить(ОписаниеПоля.Имя, ОписаниеПоля.ТипЗначения);
		Если ВключаяЗаголовоки Тогда
			НоваяКолонка.Заголовок = ОписаниеПоля.Представление;
		КонецЕсли; 
	КонецЦикла;
	Возврат Результат;
	
КонецФункции

Функция ПолучитьШаблоныВложенныхТаблиц(ОбъектМД)
	
	#Если _ Тогда
	    ОбъектМД = Метаданные.Справочники.СервисыИис;
	#КонецЕсли
	ШаблоныВложенныхТаблиц = Новый Структура;
	Для Каждого МетаТЧ Из ОбъектМД.ТабличныеЧасти Цикл
		ШаблонТаблицы = НОвый ТаблицаЗначений;
		Для Каждого МетаРеквизит Из МетаТЧ.Реквизиты Цикл
			ОписаниеТипов = МетаРеквизит.Тип;
			ОписаниеТипов = КомпактноеОписаниеТиповДляСериализации(ОписаниеТипов);
			ШаблонТаблицы.Колонки.Добавить(МетаРеквизит.Имя, ОписаниеТипов);
		КонецЦикла;
		ШаблонТаблицы.Колонки.Добавить("Ссылка", Новый ОписаниеТипов(СтрЗаменить(ОбъектМД.ПолноеИмя(), ".", "Ссылка.")));
		ШаблоныВложенныхТаблиц.Вставить(МетаТЧ.Имя, ШаблонТаблицы);
	КонецЦикла;
	Возврат ШаблоныВложенныхТаблиц;
	
КонецФункции

Процедура ПодготовитьПорциюТабличныхЧастейКСравнению(Знач ТабличныеЧасти)
	
	Для Каждого КлючИЗначение Из ТабличныеЧасти Цикл
		Если КлючИЗначение.Значение.Колонки.Количество() = 0 Тогда 
			КлючИЗначение.Значение.Колонки.Добавить("Ссылка");
		КонецЕсли; 
		Если КлючИЗначение.Значение.Индексы.Количество() = 0 Тогда
			КлючИЗначение.Значение.Индексы.Добавить("Ссылка");
		КонецЕсли; 
	КонецЦикла;

КонецПроцедуры

Функция СкопироватьТабличныеЧасти(Структура)
	
	#Если _ Тогда
	    Структура = Новый Структура
	#КонецЕсли
	Результат = Новый Структура;
	Для Каждого КлючИЗначение Из Структура Цикл
		Результат.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение.Скопировать());
	КонецЦикла;
	Возврат Результат;
	
КонецФункции

Функция ПрочитатьМетаданныеВыгрузки(Знач Сообщать = Ложь) Экспорт 
	
	ИмяФайлаМетаданных = ИмяФайлаМетаданныхСравнения(); 
	ФайлМетаданных = Новый Файл(ИмяФайлаМетаданных);
	Если Не ФайлМетаданных.Существует() Тогда
		Если Сообщать Тогда
			ирОбщий.СообщитьЛкс("Не найден файл метаданных выгрузки " + ФайлМетаданных.ПолноеИмя);
		КонецЕсли;
		Возврат Неопределено;
	КонецЕсли; 
	Результат = ирОбщий.ЗагрузитьЗначениеИзФайлаЛкс(ИмяФайлаМетаданных);
	Возврат Результат;

КонецФункции

// вывод разницы
Процедура ВывестиРазницуЧисел(Знач СтрокаРезультата, Знач РезультатСравненияСтрок, Знач КолонкиРазницы);
	
	#Если Сервер И Не Сервер Тогда
	    СтрокаРезультата = Новый ТаблицаЗначений;
		СтрокаРезультата = СтрокаТаблицы.Добавить();
		Строка2 = СтрокаТаблицы.Добавить();
	#КонецЕсли
	Если Ложь
		//Или ирКэш.РежимОтладкиЛкс() // Закомментировано для ускорения
	Тогда 
		// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
		Для Каждого ВыводимаяКолонка Из КолонкиРазницы Цикл
			Если РезультатСравненияСтрок = ПризнакТолько2 Тогда
				ЗначениеЯчейки1 = 0;
			Иначе
				ЗначениеЯчейки1 = СтрокаРезультата[ВыводимаяКолонка.ИмяКолонки + "1"];
			КонецЕсли; 
			Если РезультатСравненияСтрок = ПризнакТолько1 Тогда
				ЗначениеЯчейки2 = 0;
			Иначе
				ЗначениеЯчейки2 = СтрокаРезультата[ВыводимаяКолонка.ИмяКолонки2 + "2"];
			КонецЕсли; 
			Если Истина
				И ТипЗнч(ЗначениеЯчейки1) = Тип("Число")
				И ТипЗнч(ЗначениеЯчейки2) = Тип("Число")
			Тогда 
				СтрокаРезультата[ВыводимаяКолонка.ИмяКолонки + "Разность"] = ЗначениеЯчейки2 - ЗначениеЯчейки1;
			КонецЕсли;
		КонецЦикла;
	Иначе
		// Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru)
		Для Каждого ВыводимаяКолонка Из КолонкиРазницы Цикл  		Если РезультатСравненияСтрок = ПризнакТолько2 Тогда  			ЗначениеЯчейки1 = 0;  		Иначе  			ЗначениеЯчейки1 = СтрокаРезультата[ВыводимаяКолонка.ИмяКолонки + "1"];  		КонецЕсли;  		Если РезультатСравненияСтрок = ПризнакТолько1 Тогда  			ЗначениеЯчейки2 = 0;  		Иначе  			ЗначениеЯчейки2 = СтрокаРезультата[ВыводимаяКолонка.ИмяКолонки2 + "2"];  		КонецЕсли;  		Если Истина  			И ТипЗнч(ЗначениеЯчейки1) = Тип("Число")  			И ТипЗнч(ЗначениеЯчейки2) = Тип("Число")  		Тогда  			СтрокаРезультата[ВыводимаяКолонка.ИмяКолонки + "Разность"] = ЗначениеЯчейки2 - ЗначениеЯчейки1;  		КонецЕсли;  	КонецЦикла;  
	КонецЕсли;
КонецПроцедуры	

// цвета по-умолчанию
Процедура УстановитьСтандартныеЦвета() Экспорт 
	
	ОтличаютсяЦветФона = ирОбщий.ЦветФонаОшибкиЛкс();
	ОтличаютсяЦветТекста = Новый Цвет;
	
	ТолькоВТаблице1ЦветФона = WebЦвета.СветлоЖелтый;
	ТолькоВТаблице1ЦветТекста = Новый Цвет;
	
	ТолькоВТаблице2ЦветФона = WebЦвета.Лазурный;
	ТолькоВТаблице2ЦветТекста = Новый Цвет;

КонецПроцедуры

//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный 	Контейнер = Новый Структура();
//ирПортативный 	Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный 	Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный 		ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный 		ирПортативный.Открыть();
//ирПортативный 	КонецЕсли; 
//ирПортативный #Иначе
//ирПортативный 	ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ОбщийМодульЛкс("ирСервер");
//ирПортативный ирКлиент = ирПортативный.ОбщийМодульЛкс("ирКлиент");

УстановитьСтандартныеЦвета();
мИменаВозвращаемыхСвойств = "ВсегоРазличий, СтруктураКолонокРезультата, СравниваемыеКолонкиРезультата, РезультатСравнения";
ИмяКолонкиНомерСтроки = "НомерСтроки" + ирОбщий.СуффиксСлужебногоСвойстваЛкс() + "_";
ПризнакРавно = 1;
ПризнакНеРавно = 2;
ПризнакТолько1 = 3;
ПризнакТолько2 = 4;
НеВыводитьОдинаковыеСтроки = Истина;
//НеУчитыватьРегистр = Истина;
РасполагатьСравниваемыеЯчейкиВертикально = Истина;
ВыводитьРазницуЧисловыхКолонокСравнения = Истина;
ЗапросВыгрузки = Новый Структура;
ЗапросВыгрузки.Вставить("Параметры", Новый Структура);
ЗапросВыгрузки.Вставить("ТекстЗапроса", "ВЫБРАТЬ 1");
мИмяГруппыКлючевыхКолонок = "_ГруппаКлючевых" + ирОбщий.СуффиксСлужебногоСвойстваЛкс(); 
мИмяГруппыСравниваемыхКолонок = "_ГруппаСравниваемых" + ирОбщий.СуффиксСлужебногоСвойстваЛкс(); 
мИмяГруппыНесравниваемыхКолонок = "_ГруппаНесравниваемых" + ирОбщий.СуффиксСлужебногоСвойстваЛкс();
мИмяГруппыРазностныхКолонок = "_ГруппаРазностных" + ирОбщий.СуффиксСлужебногоСвойстваЛкс(); 
мИмяКолонкиРезультатаСравнения = "РезультатСравнения" + ирОбщий.СуффиксСлужебногоСвойстваЛкс();
мИмяКолонкиНомераСтрокиРезультата = ирОбщий.ИмяКолонкиВнутреннегоИДСтрокиЛкс();
