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

16.02.18

Разработка - Механизмы платформы 1С

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

Скачать исходный код

Наименование Файл Версия Размер
DynamicColumns
.dt 47,75Kb
5
.dt 1.0 47,75Kb 5 Скачать

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

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

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

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

 

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

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

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

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

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

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

 

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

Модуль формы

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

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

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

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

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

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

 

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

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

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

 

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

Динамические колонки в таблице значений

См. также

Сервисы интеграции без Шины и интеграции

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    2570    dsdred    16    

59

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    5935    dsdred    55    

83

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5883    YA_418728146    25    

68

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6985    dsdred    36    

113

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    19079    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12795    human_new    27    

76

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

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

28.08.2023    9416    YA_418728146    6    

143

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6531    sebekerga    54    

95
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. bulpi 215 17.02.18 14:36 Сейчас в теме
Милая девушка, это задача для новичков. Или я что-то не понял в глубине этой разработки ?
МихаилМ; +1 Ответить
2. пользователь 17.02.18 17:24
Сообщение было скрыто модератором.
...
3. пользователь 18.02.18 00:03
Сообщение было скрыто модератором.
...
4. Vasvas05 22 18.02.18 21:01 Сейчас в теме
+, взял почитать, статья хорошая и написано понятно все
user1634752; Gal4onoK_89; RomanKod; Pavel Rodinchenko; perepetulichka; +5 Ответить
5. МихаилМ 19.02.18 14:17 Сейчас в теме
это задача на профпригодность. на 30 минут.
в sql - оператор pivot.

скд легко выводит на "маленьких" объемах данных.
На 200к строк , 20 полей, 10к результирующей тз построчный способ работает быстрее, а поколоночный в разы быстрее.

также можете применить кластерный анализ объекта анализ данных.
6. tamepjlah 3 13.08.19 10:15 Сейчас в теме
Понадобилось и мне освоить динамическую таблицу. Поставленную задачу решал на примере данный обработки. Работает некорректно в случае, если, например, дата рождения в регистре сведений будет указана только у одного сотрудника. В этом случае, если сформировать таблицу, потом не закрывая обработку удалить запись с датой рождения (т.е. в таблице есть колонка ДатаРождения, но записи с датой рождения ни у одного сотрудника теперь нет в регистре сведений), то, если повторно нажать на кнопку "Сформировать" колонка с датой рождения остается на форме.
7. tamepjlah 3 13.08.19 12:33 Сейчас в теме
(6) В начало процедуры ВыполнитьНаСервере() добавил код:
	МассивПредопределенныхКолонок = Новый Массив;
	МассивПредопределенныхКолонок.Добавить("Сотрудник");
	МассивУдаляемыхРеквизитов = Новый Массив;
	МассивУдаляемыхЭлементов  = Новый Массив;
	Для Каждого ЭлементКолонка Из Элементы["Сотрудники"].ПодчиненныеЭлементы Цикл
		ЭлементПутьКДанным = ЭлементКолонка.ПутьКДанным;
		ЭлементКолонкаРеквизитИмя = СтрЗаменить(ЭлементПутьКДанным, ("Сотрудники"+"."),"");
		Если МассивПредопределенныхКолонок.Найти(ЭлементКолонкаРеквизитИмя) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		МассивУдаляемыхРеквизитов.Добавить(ЭлементПутьКДанным);
		МассивУдаляемыхЭлементов.Добавить(ЭлементКолонка);
	КонецЦикла;
	
	// Удалим динамические реквизиты и элементы(колонки), вернув таблицу формы к исходному виду.
	Если МассивУдаляемыхРеквизитов.Количество() Тогда
		ЭтаФорма.ИзменитьРеквизиты(,МассивУдаляемыхРеквизитов);
		Для Каждого ЭлементКолонка Из МассивУдаляемыхЭлементов Цикл
			Элементы.Удалить(ЭлементКолонка);
		КонецЦикла;
	КонецЕсли;		
Показать

Теперь при повторном нажатии формирование происходит корректно
Gal4onoK_89; +1 Ответить
Оставьте свое сообщение