Каталог решений - Динамические колонки в таблице значений из разного числа строк (как в отчёте)

Динамические колонки в таблице значений из разного числа строк (как в отчёте)

Динамические колонки в таблице значений из разного числа строк (как в отчёте)

В наличии

Как всегда, статья больше адресована себе, чтобы в нужный момент быстро найти.
Предыстория…
Как-то передо мной была поставлена задача сделать обработку, в которой по пользователям нужно было вывести загрузку по их активным проектам в настоящий момент. Она требовалась для руководителя, который для менее загруженного пользователя назначал бы новые проекты.
По одному и тому же проекту чаще всего были задействованы разные пользователи, число и названия проектов также различались.

Категория:

Описание

Для статьи я упростила и переделала ту же идею, только для справочника сотрудники, по которым мы выведем  в колонки сведения о них "Рост", "Вес", "Адрес регистрации" и тп.

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

Результат работы обработки:

Сведения из второй колонки преобразованы в независимые именнованные колонки со значениями. 

 

Ключевые объекты конфигурации

1. Справочник "Сотрудники".

2. Регистр сведений "СведенияОСотрудниках".

Измерения: Сотрудник, Сведение. Ресурс: Значение.

3. Обработка "ДинамическиеКолонки". 

Для измерения регистра сведений я ввела план видов характеристик "Сведения" с разнообразными типами.

 

Обработка "ДинамическиеКолонки"

Модуль формы

Код можно назвать вполне универсальным, в том смысле что, если у вас так же 3 колонки, не важно с какими наименованиями, вы можете воспользоваться им без внушительных доработок.

Я внесла в код три замечания в качестве комментариев, в которых указано, что нужно исправить.

(1) В запросе после КАК оставьте те значения, которые сейчас заданы — Сотрудник, Сведение, Значение.

После того, как протестируете и вникните в код, переименуете их. 

(2)  Укажите свой тип для колонки "Сведение", у меня это — ПВХ.

(3) Укажите свой тип для колонки "Значение", у меня это массив из типов.

 

&НаКлиенте
Процедура ВыполнитьНаКлиенте(Команда)
	ВыполнитьНаСервере()
КонецПроцедуры

&НаСервере
Процедура ВыполнитьНаСервере()
	
	Запрос = Новый Запрос;
	МенВрТаб = Новый МенеджерВременныхТаблиц;
	Запрос.МенеджерВременныхТаблиц = МенВрТаб;
	Запрос.Текст = 
	// -->> ВСТАВИТЬ СВОЙ КОД ОТСЮДА (1)
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	СведенияОСотрудниках.Сведение КАК Сведение
	|ПОМЕСТИТЬ ВТ_Сведения
	|ИЗ
	|	РегистрСведений.СведенияОСотрудниках КАК СведенияОСотрудниках
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СведенияОСотрудниках.Сотрудник КАК Сотрудник,
	|	СведенияОСотрудниках.Сведение КАК Сведение,
	|	СведенияОСотрудниках.Значение КАК Значение
	|ПОМЕСТИТЬ ВТ_СведенияОСотрудниках
	|ИЗ
	|	РегистрСведений.СведенияОСотрудниках КАК СведенияОСотрудниках
	|;
	|
	// <<-- СЮДА
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ВТ_Сведения.Сведение КАК Сведение
	|ИЗ
	|	ВТ_Сведения КАК ВТ_Сведения";
	
	РезультатЗапроса = Запрос.Выполнить();
	НаименованияСведений = РезультатЗапроса.Выгрузить();
	
	Если НЕ РезультатЗапроса.Пустой() Тогда
		
		ТЗСведений = Новый ТаблицаЗначений;
		
		Индекс=0;
		Для каждого Наименование Из НаименованияСведений Цикл
			Если ЗначениеЗаполнено(Наименование.Сведение) Тогда
				ИмяКолонки = "ИмяКолонки"+Индекс;
				// -->> ЗДЕСЬ УКАЖИТЕ СВОЙ ТИП КОЛОНКИ "СВЕДЕНИЕ" (2) 
				ТЗСведений.Колонки.Добавить(ИмяКолонки,Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.Сведения"),Наименование.Сведение);
				Индекс = Индекс+1;
			КонецЕсли;
		КонецЦикла; 
		
		Индекс=0;
		Для каждого Наименование Из НаименованияСведений Цикл
			Если ЗначениеЗаполнено(Наименование.Сведение) Тогда
				НоваяСтрока = ТЗСведений.Добавить();
				НоваяСтрока["ИмяКолонки"+Индекс]=Наименование.Сведение;
				Индекс = Индекс+1;
			КонецЕсли;
		КонецЦикла; 	
		
		ТекстЗапроса = 
		"ВЫБРАТЬ
		|	ТЗСведений.Сведение
		|ПОМЕСТИТЬ ВТСведений
		|ИЗ
		|	&ТЗСведений КАК ТЗСведений
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ВТСведений.Сведение,
		|	ВТ_СведенияОСотрудниках.Сотрудник
		|ИЗ
		|	ВТ_СведенияОСотрудниках КАК ВТ_СведенияОСотрудниках
		|		ЛЕВОЕ СОЕДИНЕНИЕ ВТСведений КАК ВТСведений
		|		ПО ВТСведений.Сведение = ВТ_СведенияОСотрудниках.Сведение";
		
		КоличествоОставшихсяСтрок = ТЗСведений.Количество();
		ТекстЗапросаКТЗСведений = "";
		ТекстЗапросаК_ВТСведений = "";
		
		Для каждого Колонка Из ТЗСведений.Колонки Цикл
			
			ТекстЗапросаКТЗСведений = ТекстЗапросаКТЗСведений + "ТЗСведений."+Колонка.Имя;
			ТекстЗапросаК_ВТСведений = ТекстЗапросаК_ВТСведений + "ВЫБОР КОГДА ВТ_СведенияОСотрудниках.Сведение = ВТСведений."+Колонка.Имя+" ТОГДА ВТ_СведенияОСотрудниках.Значение ИНАЧЕ """" КОНЕЦ КАК "+Колонка.Имя;
			Если КоличествоОставшихсяСтрок > 1 Тогда
				ТекстЗапросаКТЗСведений = ТекстЗапросаКТЗСведений+","+Символы.ПС+Символы.Таб;
				ТекстЗапросаК_ВТСведений = ТекстЗапросаК_ВТСведений+","+Символы.ПС+Символы.Таб;
			КонецЕсли;
			КоличествоОставшихсяСтрок = КоличествоОставшихсяСтрок-1;
			
		КонецЦикла;
		
		ЗаменаЗапросаКТЗСведений = СтрЗаменить(ТекстЗапроса,"ВЫБРАТЬ"+Символы.ПС+Символы.Таб+"ТЗСведений.Сведение","ВЫБРАТЬ"+Символы.ПС+Символы.Таб+ТекстЗапросаКТЗСведений);
		ЗаменаЗапросаК_ВТСведений = СтрЗаменить(ЗаменаЗапросаКТЗСведений,"ВЫБРАТЬ"+Символы.ПС+Символы.Таб+"ВТСведений.Сведение","ВЫБРАТЬ"+Символы.ПС+Символы.Таб+ТекстЗапросаК_ВТСведений);
		ТекстЗапросаУсловия = "";
		
		Если ТЗСведений.Колонки.Количество() >0 Тогда
			Флаг = Истина;
			Для каждого Колонка Из ТЗСведений.Колонки Цикл
				Если Флаг Тогда
					Флаг = Ложь;
					ТекстЗапросаУсловия = ТекстЗапросаУсловия+"ПО ВТСведений."+Колонка.Имя+" = ВТ_СведенияОСотрудниках.Сведение";
					ЗаменаУсловияЗапроса = СтрЗаменить(ЗаменаЗапросаК_ВТСведений,"ПО ВТСведений.Сведение = ВТ_СведенияОСотрудниках.Сведение",ТекстЗапросаУсловия);	
					Продолжить;
				КонецЕсли;
				ЗаменаУсловияЗапроса = ЗаменаУсловияЗапроса + " ИЛИ ВТСведений."+Колонка.Имя+" = ВТ_СведенияОСотрудниках.Сведение";	
				
			КонецЦикла;
			ЗаменаУсловияЗапроса = ЗаменаУсловияЗапроса;
		КонецЕсли;
		
		Запрос = Новый Запрос;
		Запрос.МенеджерВременныхТаблиц = МенВрТаб;
		Запрос.Текст = ЗаменаУсловияЗапроса;
		Запрос.УстановитьПараметр("ТЗСведений",ТЗСведений);
		ТаблицаРезультата = Запрос.Выполнить().Выгрузить();	
		
		// -->> ЗАДАЙТЕ СВОИ ТИПЫ ДЛЯ КОЛОНКИ "ЗНАЧЕНИЕ" (3)
		МассивТипов=Новый Массив(); 
		МассивТипов.Добавить(Тип("Строка"));
		МассивТипов.Добавить(Тип("Дата"));
		МассивТипов.Добавить(Тип("Число"));
		МассивТипов.Добавить(Тип("Булево"));
		МассивТипов.Добавить(Тип("ПеречислениеСсылка.Пол"));
		МассивТипов.Добавить(Тип("СправочникСсылка.ЗначенияСведений"));
		
		Для каждого Колонка Из ТЗСведений.Колонки Цикл
			
			МоиСотрудники = ДанныеФормыВЗначение(Сотрудники, Тип("ТаблицаЗначений"));
			Если НЕ ЕстьКолонка(Колонка.Имя,МоиСотрудники.Колонки) Тогда
				нРеквизиты = Новый Массив;
				нРеквизиты.Добавить(Новый РеквизитФормы(Колонка.Имя, Новый ОписаниеТипов(МассивТипов,,,,Новый КвалификаторыСтроки(25),Новый КвалификаторыДаты(ЧастиДаты.Дата)), "Сотрудники", Колонка.Заголовок));
				
				ИзменитьРеквизиты(нРеквизиты);
				
				нЭлемент = Элементы.Добавить(Колонка.Имя, Тип("ПолеФормы"), Элементы.Сотрудники); 
				нЭлемент.Вид = ВидПоляФормы.ПолеВвода; 
				нЭлемент.ПутьКДанным = "Сотрудники."+Колонка.Имя;
			КонецЕсли;
			
		КонецЦикла;
		
		
		Для Индекс = -ТаблицаРезультата.Количество()+1 По 0 Цикл	 		
			
			Запись = ТаблицаРезультата.Получить(-Индекс);
			ПараметрыОтбора = Новый Структура("Сотрудник", Запись.Сотрудник);
			НайденныеЗаписи = ТаблицаРезультата.НайтиСтроки(ПараметрыОтбора);
			Если НайденныеЗаписи.Количество()>1 Тогда 
				Для каждого Колонка Из ТЗСведений.Колонки Цикл
					Если ЗначениеЗаполнено(Запись[Колонка.Имя]) Тогда
						НайденныеЗаписи[0][Колонка.Имя] = Запись[Колонка.Имя];
					КонецЕсли;
				КонецЦикла;
				ТаблицаРезультата.Удалить(Запись);
			КонецЕсли;
			
		КонецЦикла;	
		
		Сотрудники.Загрузить(ТаблицаРезультата);
	КонецЕсли;
	
КонецПроцедуры

Функция ЕстьКолонка(ИмяКолонки, Колонки) 
	
	Есть = ?(Колонки.Найти(ИмяКолонки) = Неопределено, Ложь, Истина);
	
	Возврат Есть;
	
КонецФункции // ЕстьКолонка()

 

На всякий случай прилагаю базу.

has been added to your cart:
Оформление заказа