Кросс-таблица из табличной части или запроса

27.09.16

Разработка - Запросы

Данная задача встречалась мне несколько раз. Каждый раз в новой интерпретации, но суть примерно одинаковая: "Хочу, чтобы по строкам были товары, по колонкам склады, а на пересечении - количество". Вместо товары-склады, может быть что угодно: дата-контрагент, номенклатура+цвет - размер и т.д.

Скачать файлы

Наименование Файл Версия Размер
Пример Кросс-таблица (ОФ, УФ, 8.3)
.epf 20,23Kb
115
.epf 20,23Kb 115 Скачать

Для примера возьмем некоторый документ с табличной частью Остатки на конец смены. Структура полей табличной части представлена на рисунке справа.

Заказчику неудобно работать с ней в таком виде, и он желает просматривать ее и редактировать в виде кросс-таблицы, как на рисунке слева.
Замечание: на картинке приводится две таблицы одновременно для наглядности. В реальных задачах обычно требуется отображать только кросс-таблицу.

Основная сложность в сопоставлении колонок кросс-таблицы с соответствующими строками табличной части. Ниже представлены три процедуры, которые решают данную задачу за несколько строк кода. Вот пример их использования:

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

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

Небольшие пояснения:
1. Дополнительная информация для связи между исходной и конечной таблицами хранится в служебной таблице. Ее необходимо сохранять на протяжении всей работы с кросс-таблицей. Ее структура простая: Имя, Заголовок и Тип колонок, а также имена полей табличной части, по сочетанию которых будут создаваться колонки. В моем примере это одно поле “Стеллаж”, но их может быть и несколько, например “Номенклатура,Характеристика”. Для рассматриваемого примера структура служебной таблицы с данными представлена на рисунке

 

2. Прямое преобразование состоит из двух шагов: 
     - генерируем идентификаторы колонок для кросс-таблицы, заполняем заголовки и типы дополнительных полей. В моем примере в заголовок я пишу наименование стеллажа, тип на пересечении горизонтальных группировок - числовой.
     - получаем кросс-таблицу

Сами процедуры
// Пусть нужно по некоторой таблице значений создать другую таблицу значений
// При этом колонки второй таблицы соответствуют сочетанию полей в первой таблице 
// (например, в первой таблице одна колонка Номенклатура, а во второй должна быть отдельная колонка для каждой номенклатуры)
// Тогда первую таблицу будем для краткости называть ДАННЫЕ, а вторрую КРОССТАБЛИЦА

// для решения этой задачи потребуется дополнительная таблица, которую будем назывть
// ИДЕНТИФИКАТОРЫКОЛОНОК

// Данный алгоритм выполняет преобразования 
//		- ДАННЫЕ (1)-> ИДЕНТИФИКАТОРЫКОЛОНОК (2)-> КРОССТАБЛИЦА
//		- КРОССТАБЛИЦА (3)-> ДАННЫЕ

Функция ПолучитьИдентификаторыДанных(тДанные, стрПоляВертикальныхГруппировок) Экспорт
	
	тИдентификаторыКолонок = тДанные.Скопировать(,стрПоляВертикальныхГруппировок);
	тИдентификаторыКолонок.Свернуть(стрПоляВертикальныхГруппировок);
	
	тИдентификаторыКолонок.Колонки.Добавить("Имя");
	тИдентификаторыКолонок.Колонки.Добавить("Заголовок");
	тИдентификаторыКолонок.Колонки.Добавить("Тип");
	
	Для сч = 1 по тИдентификаторыКолонок.Количество() Цикл
		тИдентификаторыКолонок[сч-1].Имя = "Группировка_" + Формат(сч, "ЧЦ=5; ЧВН=; ЧГ=0");
	КонецЦикла;
	
	Возврат тИдентификаторыКолонок;
	
КонецФункции

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

Функция ТрансформироватьКроссТаблицуВДанные(тКроссТаблица, тИдентификаторыКолонок, ИмяКолонкиРесурс) Экспорт
	
	тДанные = Новый ТаблицаЗначений;
	тДанные.Колонки.Добавить(ИмяКолонкиРесурс);
	
	Для каждого Колонка из тКроссТаблица.Колонки Цикл
		Если Найти(Колонка.Имя, "Группировка_") = 1 Тогда
			Продолжить;
		КонецЕсли;
		
		тДанные.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения);
	КонецЦикла;
	
	Для каждого Колонка из тИдентификаторыКолонок.Колонки Цикл
		Если Колонка.Имя = "Имя" Тогда
			Продолжить;
		ИначеЕсли Колонка.Имя = "Заголовок" Тогда
			Продолжить;
		КонецЕсли;
		
		тДанные.Колонки.Добавить(Колонка.Имя);
	КонецЦикла;
	
	Для каждого КолонкаОтображения из тКроссТаблица.Колонки Цикл
		Если НЕ Найти(КолонкаОтображения.Имя, "Группировка_") = 1 Тогда
			Продолжить;
		КонецЕсли;
		
		СтрокаСоответствияКолонок = тИдентификаторыКолонок.Найти(КолонкаОтображения.Имя, "Имя"); // Строка должна быть найдена ВСЕГДА. Иначе это несоблюдение требований алгоритма - будет выдана программная ошибка
		
		Для каждого СтрокаОтображения из тКроссТаблица Цикл
			
			Значение = СтрокаОтображения[КолонкаОтображения.Имя];
			Если НЕ ЗначениеЗаполнено(Значение) Тогда
				Продолжить;
			КонецЕсли;
			
			НоваяСтрока = тДанные.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаОтображения);
			ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаСоответствияКолонок);
			НоваяСтрока[ИмяКолонкиРесурс] = Значение;
			
		КонецЦикла;
		
	КонецЦикла;
	
	Возврат тДанные;
	
КонецФункции

Отмечу также, что данные методы можно использовать не только для разворачивания табличной части, но и таблицы из запроса (например, в АРМе)

Процедуры тестировались на платформе 8.3 в режиме совместимости с 8.2. Однако скорее всего будут работать и на платформе 8.1

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

Процедуры кросс-таблица транспорировать транспорирование

См. также

Infostart Toolkit: Инструменты разработчика 1С 8.3 на управляемых формах

Инструментарий разработчика Роли и права Запросы СКД Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

13000 руб.

02.09.2020    119908    656    389    

701

Для чего используют конструкцию запроса "ГДЕ ЛОЖЬ" в СКД на примере конфигурации 1С:ERP

Запросы СКД Платформа 1С v8.3 Запросы Система компоновки данных 1С:ERP Управление предприятием 2 Бесплатно (free)

В типовых конфигурациях разработчики компании 1С иногда используют в отчетах, построенных на СКД, такую конструкцию, как "ГДЕ ЛОЖЬ". Такая конструкция говорит о том, что данные в запросе не будут получены совсем. Для чего же нужен тогда запрос?

13.02.2024    5618    KawaNoNeko    23    

23

Набор-объект для СКД по тексту или запросу

Запросы СКД Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Абонемент ($m)

Есть список полей в виде текста, или запрос - закидываем в набор СКД.

1 стартмани

31.01.2024    1964    2    Yashazz    0    

29

Запрос 1С copilot

Инструментарий разработчика Запросы Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Абонемент ($m)

Пишем на человеческом языке, что нам надо, и получаем текст запроса на языке 1С. Используются большие языковые модели (LLM GPT) от OpenAI или Яндекс на выбор.

5 стартмани

15.01.2024    6089    29    mkalimulin    23    

48

PrintWizard: поддержка представлений ЗУП в конструкторе

Инструментарий разработчика Запросы Платформа 1С v8.3 Бесплатно (free)

Одной из интересных задач, стоящих в процессе разработки, была поддержка механизма представлений в ЗУП. Но не просто возможность исполнения запросов с ними. Основная проблема была в том, чтобы с ними было удобно работать, а именно: создавать, модифицировать и отлаживать. Кратко о том, что в итоге получилось...

14.12.2023    1714    vandalsvq    7    

28

Объектная модель запроса "Схема запроса" 2

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

Далеко уже не новый тип данных "Схема запроса". Статья о том, как использовать его "попроще". Примеры создания текста запроса с нуля и изменение имеющегося запроса.

06.12.2023    5282    user1923546    26    

43

Начните уже использовать хранилище запросов

HighLoad оптимизация Запросы

Очень немногие из тех, кто занимается поддержкой MS SQL, работают с хранилищем запросов. А ведь хранилище запросов – это очень удобный, мощный и, главное, бесплатный инструмент, позволяющий быстро найти и локализовать проблему производительности и потребления ресурсов запросами. В статье расскажем о том, как использовать хранилище запросов в MS SQL и какие плюсы и минусы у него есть.

11.10.2023    15954    skovpin_sa    14    

97
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Hatson 528 19.09.16 11:43 Сейчас в теме
Хм, ну надо же))
А через неделю я опубликовал свою статью про СКД.

http://infostart.ru/public/549297/

Задам провокационный вопрос:
А что делать если в одной кросс-таблице нужно свести данные из нескольких реальных таблиц (табличных частей) с разной детализацией?
2. json 3294 19.09.16 23:30 Сейчас в теме
(1) Hatson, оба способа имеют право на существование. Все зависит от предпочтений программиста и требований клиента.
Я изначально тоже хотел сделать через СКД, когда у меня встала такая задача. Но ключевому пользователю показалось неудобно редактировать в табличном документе. В итоге родился данный способ, который был уже применен несколько раз мной и коллегами.

По поводу твоего вопроса - да можно сделать, например вывести учетный остаток по складу в моем примере. Также приходилось делать и группировки. Все это ложится в данную схему при желании. Кроме того, хитрые соединения при редактировании табличной части - не такое уж и частое явление. В большинстве случаев достаточно просто построить кросс-таблицу

В схеме с СКД экономятся силы программиста на выводе и тратятся на редактировании. В схеме с табличным полем - наоборот. Все равно думать надо и в том и другом случае.
3. topasha 23 13.10.16 00:45 Сейчас в теме
Вот спасибо, хороший человек! Кучу времени мне сэкономил.
4. user702069_savel777v2 03.03.17 15:35 Сейчас в теме
Столкнулся с аналогичной задачей при разработке нового документа. В первой ТЧ документа Электроприборы, по второй их лимиты в разрезе Периодов. Весь код yurii_host "тащить" постеснялся, реализовал свою реализацию с вашей изначальной идеей. Т.е. КроссТаблица + одна вспомогательная таблица которая хранит соответствие номеров колонок и периодов.
всё бы хорошо... но вот когда в документ понадобилось ещё и итоги по колонкам добавить..... тут я встрял...
В 8.3 итогов у ТаблицаЗначений нет, а значит + ещё куча обработчиков...
потому посчитал проще переделать на СКД (по типу Hatson) + обработчики расшифровки...
Потому могут предметно говорить о выгодах того или иного варианта:
1 Таблица хорошо, когда ресурсов немного, нет требований к оформлению, т. е. когда задача условно мала. Тогда "ваять" СКД + обработчики будет затратнее...
Во всех остальных случаях лучше СКД, преимуществ немало:
1. Простота обслуживания. после итогов внес ещё не мало правок по форме вывода информации, заголовков, выводимых итогов и т.д. Даже не представляю как я это делал бы на таблице.
2. Переносил тот же код на другие документы с теми же задачами... СКД переносится легче, меньше реквизитов формы и процедур обработчиков.
3. СКД работает заметно быстрее при перемещениях по таблице (видно даже субъективно для отладки юзал одни и те же доки двумя разными формами)...
В целом рекомендую делать на СКД...
П,С. Обоим авторам благодарность на красивые идеи!
5. andrey80nik 3 14.06.23 11:20 Сейчас в теме
Намекните какую функцию надо поправить чтобы можно было колонки произвольно добавлять сразу в кросс таблицу?
6. vik2006 137 03.10.23 04:56 Сейчас в теме
(5) Да, присоединяюсь к вопросу. А как быть, если нужно несколько колонок добавить, например, Количество, Цена и Сумма?
7. vik2006 137 15.11.23 03:08 Сейчас в теме
Доброго времени суток, автор. А как быть, если нужно несколько колонок добавить, например, Количество, Цена и Сумма?
Оставьте свое сообщение