1с сгруппировать таблицу значений

Обновлено: 08.07.2024

Давно заметил, что ничего так не радует глаз пользователя и не заставляет его ценить твою профпригодность как наличие множества "галочек", "штучек", "пимпочек" и кнопочек на экранной форме. Ну, конечно, при условии, что все они работают и работают правильно. У меня обычно выходило так, что большинство написанных отчетов обрастали по меньшей мере еще третью от первоначального количества опций, а код угрожающе кренился в полную сумятицу от перегрузки условными операторами и дополнительными переменными.

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

У каждого программиста есть свой способ выводить ТЗ на печать по нужным группировкам - кто то использует класс индексированных таблиц, а кто-то сам вводит в ТЗ индексы, а может есть и еще более или менее эффективные способы. Речь сейчас не о них.

Столкнувшись недавно с проблемой наличия просто сумасшедшего количества необходимых пользователю вариантов группировки данных для вывода на печать да еще и слитых из двух разных конфигураций твердо решил засунуть построение итоговой таблицы значений в одну процедуру. Независимо от количества групп и нужного пользователю порядка их следования.

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

В чистом остатке мы получили 1(одну) функцию получения предназначенной для печати таблицы значений для любых возможных вариантов группировки и очень простую печатную форму для опять же любого варианта отчета.

Макет печаной формы приведен на картинке, а сама функция звучит так:

Функция ИтоговаяПоГруппировкамТЗ ( исхТЗ , СтрГруппировок , СтрИтогов , ДобУровень = 0 )

Если (ПустоеЗначение( СтрГруппировок ) = 1 ) Или (ПустоеЗначение( СтрИтогов ) = 1 ) Тогда

Предупреждение( "Не отмечены поля группировок или поля итогов. " );

ТЗ = СоздатьОбъект( "ТаблицаЗначений" );

исхТЗ . Выгрузить ( ТЗ . СтрГруппировок + "," + СтрИтогов );

ТЗ . Свернуть ( СтрГруппировок , стрИтогов );

ТЗИтогов = СоздатьОбъект( "ТаблицаЗначений" );

ТЗ . Выгрузить ( ТЗИтогов );

спТаблиц = СоздатьОбъект( "СписокЗначений" );

спСвертки = СоздатьОбъект( "СписокЗначений" );

сДляСписка = СтрЗаменить( стрГруппировок , "," ,РазделительСтрок);

Для ф = 1 По СтрКоличествоСтрок( сДляСписка ) Цикл

спСвертки . ДобавитьЗначение (СтрПолучитьСтроку( сДляСписка , ф ));

Для ф = 1 По спСвертки . РазмерСписка ()- 1 Цикл

времТ = СоздатьОбъект( "ТаблицаЗначений" );

ТЗ . Выгрузить ( времТ );

свернутьПо = свернутьПо + ?( ф = 1 , "" , "," ) + спСвертки . ПолучитьЗначение ( ф );

времТ . Свернуть ( свернутьПо , СтрИтогов );

спТаблиц . ДобавитьЗначение ( времТ , свернутьПо );

Если ДобУровень = 1 Тогда

ТЗ . НоваяКолонка ( "Уровень_Группировки" , "Число" );

Для ф = 1 По спТаблиц . РазмерСписка () Цикл

времТ = СпТаблиц . ПолучитьЗначение ( ф );

Пока ВремТ . ПолучитьСтроку () = 1 Цикл

Для ы = 1 По ВремТ . КоличествоКолонок () Цикл

идКолонки = времТ . ПолучитьПараметрыКолонки ( ы );

текЗнач = ВремТ . ПолучитьЗначение ( времТ . НомерСтроки , идКолонки );

ТЗ . УстановитьЗначение ( ТЗ . НомерСтроки , идКолонки , текЗнач );

Если ДобУровень = 1 Тогда

ТЗ . УстановитьЗначение ( ТЗ . НомерСтроки , "Уровень_Группировки" , ф );

ТЗ . Сортировать ( стрГруппировок );

ИсхТЗ - это обычная таблица значений, как на первом рисунке, а возвращаемая таблица значений показана на втором рисунке.

СтрГруппировок - это обычная строка с разделенными запятыми идентификаторами полей группировки.

А СтрИтогов - строковое выражение из идентификаторов суммируемых при группировке колонок.

Когда родилась универсальная функция возникла идея сделать ее логичное продолжение - универсальную обработку. Универсальная группировка и универсальная печать любой переданной параметром таблицы значений должна, имхо, сильно пригодиться в том случае когда удается получить таблицу значений, а вот с группировками и печатью заморачиваться некогда или не хочется, да и заказчик сам толком не понимает в каком виде ему будет удобнее анализировать данные (а скорее всего в каких видах). Обработка имеет и демо режим запуска без переданной таблицы значений - в этом случае ТЗ будет сгенерирована автоматически и весь функционал обработки можно будет оценить без построения ненужной ТЗ передачи ее с вызовом из ненужной обработки.

Еще как опцию ввел в обработку фильтр значений ТЗ. Сначала думал, отбор можно сделать предварительно, до передачи таблицы в обработку, но раз уж делать универсальную фабрику изготовления отчетов, то нужно развязать руки разработчику и в этом вопросе.

Если обработку немного допилить, то можно кроме ТЗ передавать параметром опции группировки и подведения итогов и сразу группировать и вызывать печать, не показывая формы. Тоже удобно, но интерфейсы отбора и настройки вывода данных нужно каждый раз писать в вызывающем отчете. Если хочется, то почему бы и нет:)

Последний из передаваемых аргументов функции сортировки - это флаг добавления в таблицу результата колонки с уровнем группировки. При ДобУровень установленном на 1 таблица значений на выходе получает еще одну колонку Уровень_Группировки, которая заполняется числами от 1 (самый главный уровень) по возрастающей. В соответствии с признаком группировки и используется секция печатной формы для вывода соответствующей строки сгруппированной таким образом таблицы значений. Так как количество секций для уровней в печатной форме в принципе не может быть бесконечным (в отличие от потенциального количества группируемых колонок), то в печатную форму введена секция для уровня 0, который используется для вывода всех уровней группировки корорых нет в подготовленной нами печатной форме. Я лично разместил пять секций для возможных уровней (дальше фантазия иссякла), а это значит что все уровне начиная с шестого буду выводиться на печать в дизайне секции "Уровень_0"

Форум

Создание таблицы значений
Таблица значений - это двумерный массив в 1С, который предназначен для хранения и обработки промежуточных данных, возникающих в процессе работы программы. Таблица значений часто применяется при программировании на 1С, потому что имеет множество полезных возможностей и работает очень быстро. Таблица значений создается в памяти и не сохраняется в базе данных, т.е. это временный набор данных.

ТабЗнач.НоваяКолонка("Номер");
ТабЗнач.НоваяКолонка("Сотрудник");
ТабЗнач.НоваяКолонка("Должность");
ТабЗнач.НоваяКолонка("Оклад");

//можно указать тип данных каждой колонки
//если тип данных колонки не указан, то можно хранить данные любого типа
Синтаксис: НоваяКолонка(<Идентификатор>, <Тип>, <Длина>, <Точность>, <Заголовок>, <Ширина>, <Формат>, <Положение>)

ТабЗнач.НоваяКолонка("Номер","Число",10,0);
ТабЗнач.НоваяКолонка("Сотрудник","Справочник.Сотрудники");
ТабЗнач.НоваяКолонка("Должность","Справочник.Должности");
ТабЗнач.НоваяКолонка("Оклад","Число",10,2);

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

ТабЗнач.НоваяСтрока();
ТабЗнач.Номер = 1;
ТабЗнач.Сотрудник = "Иванов Иван Иванович"; //следите за типом колонки!
ТабЗнач.Должность = "Программист";
ТабЗнач.Оклад = 20000;

ТабЗнач.НоваяСтрока();
ТабЗнач.Номер = 2;
ТабЗнач.Сотрудник = "Петров Петр Петрович";
ТабЗнач.Должность = "Бухгалтер";
ТабЗнач.Оклад = 10000;

//обычно строки добавляются в цикле
СпрСотр = СоздатьОбъект("Справочник.Сотрудники");
СпрСотр.ВыбратьЭлементы();
Пока СпрСотр.ПолучитьЭлемент()=1 Цикл
. ТабЗнач.НоваяСтрока();
. ТабЗнач.Номер = СпрСотр.Код;
. ТабЗнач.Сотрудник = СпрСотр.ТекущийЭлемент(); //следите за типом колонки!
. ТабЗнач.Должность = СпрСотр.Должность;
. ТабЗнач.Оклад = СпрСотр.Оклад;
КонецЦикла;

Перебор строк таблицы значений

ТабЗнач.ВыбратьСтроки();
Пока ТабЗнач.ПолучитьСтроку()=1 Цикл
. Сообщить(ТабЗнач.Сотрудник);
КонецЦикла;

2-й способ.

Для НомерСтроки = 1 По ТабЗнач.КоличествоСтрок() Цикл
. ТабЗнач.ПолучитьСтрокуПоНомеру(НомерСтроки);
. Сообщить(ТабЗнач.Сотрудник);
КонецЦикла;

Сортировка таблицы значений

//сортировать по должности по возрастанию
ТабЗнач.Сортировать("Должность+");

//сортировать по должности по возрастанию, а внутри должности по убыванию оклада
ТабЗнач.Сортировать("Должность+,Оклад-");

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

Синтаксис: НайтиЗначение(<Знач>,<Строка>,<Колонка>)
Возвращает число: 0 - значение не найдено; 1 - значение найдено
Если указан параметр <Строка>, то поиск производится только по заданной строке
Если указан параметр <Колонка>, то поиск производится только по заданной колонке

номстр = 0;
Если ТабЗнач.НайтиЗначение (10000, номстр, "Оклад") = 1 Тогда
. ТабЗнач.ПолучитьСтрокуПоНомеру(номстр);
. Сообщить(ТабЗнач.Сотрудник);
КонецЕсли;

Итоги и группировка таблицы значений

//получить итог по колонке можно методом Итог
ВсеОклады = ТабЗнач.Итог("Оклад")

//часто требуется группировать строки и подсчитывать итоги по группам,
//в этом случае применяется метод Свернуть

//проссумировать оклады по каждой должности
ТабЗнач.Свернуть("Должность","Оклад");

//Можно группировать и суммировать сразу по нескольким колонкам
ТабЗнач.Свернуть("Категория, Должность","Оклад,Налог");

Удаление строк и колонок из таблицы значений

ТабЗнач.Очистить(); //очистить таблицу значений и удалить колонки

ТабЗнач.УдалитьСтроки(); //удаляет все строки (колонки сохраняются)

ТабЗнач.УдалитьСтроку(); //удаляет текущую строку
ТабЗнач.УдалитьСтроку(3); //удаляет 3-ю строку

ТабЗнач.УдалитьКолонку("Оклад"); //удаляет колонку Оклад
ТабЗнач.УдалитьКолонку(2); //удаляет 2-ю колонку

ВНИМАНИЕ
Часто требуется удалить строки, удовлетворяющие определенному условию.
Так как при удалении строки из таблицы значений следующая строка становится текущей,
то указанная ниже программа может удалить НЕ ВСЕ необходимые строки.

//ЭТА ПРОГРАММА НЕПРАВИЛЬНАЯ .
ТабЗнач.ВыбратьСтроки();
Пока ТабЗнач.ПолучитьСтроку()=1 Цикл
. Если <условие> Тогда
. ТабЗнач.УдалитьСтроку(); //следующая строка стала текущей,
. КонецЕсли;
КонецЦикла;

В этом случае я рекомендую использовать следующий прием:

ТабЗнач.ВыбратьСтроки();
Пока ТабЗнач.ПолучитьСтроку()=1 Цикл

начало:
. Если <условие> Тогда
. ТабЗнач.УдалитьСтроку(); //следующая строка стала текущей
. Если ТабЗнач.НомерСтроки<>0 Тогда
. Перейти

начало;
. КонецЕсли;
. КонецЕсли;
КонецЦикла;

А вот еще один правильный алгоритм, предложенный Wlad:

ТабЗнач.выбратьстроки();
Пока ТабЗнач.ПолучитьСтроку()=1 Цикл
. Пока (<условие>) и (ТабЗнач.НомерСтроки<>0) Цикл
. ТабЗнач.УдалитьСтроку(); //следующая строка стала текущей
. КонецЦикла;
КонецЦикла;

Таблица значений как элемент диалога
Таблица значений может использоваться в экранных формах как элемент диалога с пользователем.

//установить курсор на указанную колонку или можно узнать, где находится курсор
ТабЗнач.ТекущаяКолонка(НоваяКолонка,ТекКолонка);

//установить курсор на указанную строку или можно узнать, где находится курсор.
ТекСтрока = ТабЗнач.ТекущаяСтрока(НовСтрока);

ТабЗнач.ВидимостьКолонки("Оклад",0); //скрыть колонку Оклад
ТабЗнач.ВидимостьКолонки("Должность, Сотрудник",1); //показать колонки Должность и Сотрудник
ТабЗнач.ВидимостьКолонки("Оклад",1,1); //показать колонку Оклад в 1-й позиции

//можно зафиксировать верхние строки и левые колонки для удобства прокрутки таблицы значений в диалоге
ТабЗнач.Фиксировать(КолСтрок,КолКолонок);

Методы УстановитьЗначение и ПолучитьЗначение
Эти методы позволяют обращаться к данным в таблице значений для чтения и записи.
Они могут пригодиться в особых случаях при написании универсальных программ (мастеры отчетов и т.д.).

Синтаксис: УстановитьЗначение(<Строка>,<Колонка>,<Знач>)
Синтаксис: ПолучитьЗначение(<Строка>,<Колонка>)

ТабЗнач.НоваяСтрока();
ТабЗнач.УстановитьЗначение(1,"Номер",100);
ТабЗнач.УстановитьЗначение(1,"Сотрудник","Иванов Иван Иванович");
ТабЗнач.УстановитьЗначение(1,3,10000); //обращение к 1-й строке и 3-й колонке ("Оклад")

Номер = ТабЗнач.ПолучитьЗначение(1,"Номер");
ФИО = ТабЗнач.ПолучитьЗначение(1,"Сотрудник");
Оклад = ТабЗнач.ПолучитьЗначение(1,3); //обращение к 1-й строке и 3-й колонке "Оклад"

Выгрузка таблицы значений

//выгрузить 10 сотрудников с наибольшими окладами в новую таблицу значений
ТабЗнач.Сортировать("Оклад-");
ТабЗнач.Выгрузить(НоваяТабЗнач,1,10,"Сотрудник,Оклад");

Войдите как ученик, чтобы получить доступ к материалам школы

Язык запросов 1С 8.3 для начинающих программистов: группировка

Автор уроков и преподаватель школы: Владимир Милькин

Группировка в запросах

Давайте запросим из таблицы Справочник.Еда следующие реквизиты: Наименование, Цвет и Калорийность:

01

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

Алгоритм для жёлтого цвета будет такой:

  1. Находим все строчки у которых в поле Цвет стоит Жёлтый.
  2. Это будут строчки №1, 6, 8 и 9.
  3. Суммируем поле Калорийность для каждой из этих строк: 89 + 31 + 340 + 536
  4. Получаем, что для жёлтого цвета суммарная калорийность равна 996.

И так для каждого цвета.

Описанный выше процесс называется группировкой . Таким образом, группировка - это "схлопывание" (свёртка) строчек таблицы по определенному признаку.

При группировке все поля делятся на две группы:

  • Группировочные - это как раз те поля, по которым идёт свёртка. В нашем случае таким полем является Цвет.
  • Группируемые - это те поля, которые сворачиваются (схлопываются, объединяются). В нашем случае таким полем является Калорийность.

01

Группируемые поля не могут быть сами по себе. К ним обязательно применяется одна из агрегатных функций: СУММА, СРЕДНЕЕ, МИНИМУМ, МАКСИМУМ, КОЛИЧЕСТВО, КОЛИЧЕСТВО РАЗЛИЧНЫЕ:

02

Агрегатная функция СУММА

Это как раз случай, который мы разбирали. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь. Все строки группируются по группировочным полям (Цвет), а группируемые поля (Калорийность) суммируются:

сумма

Агрегатная функция СРЕДНЕЕ

В этом случае все строки группируются по группировочным полям (Цвет), а среди группируемых полей (Калорийность) находится среднее значение:

среднее

Агрегатная функция МИНИМУМ

В этом случае все строки группируются по группировочным полям (Цвет), а среди группируемых полей (Калорийность) находится минимальное значение:

минимум

Агрегатная функция МАКСИМУМ

В этом случае все строки группируются по группировочным полям (Цвет), а среди группируемых полей (Калорийность) находится максимальное значение:

максимум

Агрегатная функция КОЛИЧЕСТВО

В этом случае все строки группируются по группировочным полям (Цвет), а среди группируемых полей (Калорийность) находится их количество :

количество

Агрегатная функция КОЛИЧЕСТВО РАЗЛИЧНЫЕ

В этом случае все строки группируются по группировочным полям (Цвет), а среди группируемых полей (Калорийность) находится количество элементов с различными значениями:

количество различные

Функция КОЛИЧЕСТВО РАЗЛИЧНЫЕ требует пояснения, потому что на выбранном примере её результат совпадает с функцией КОЛИЧЕСТВО. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь. Вот более показательный пример, который всё объясняет:

03

Группировка без группируемых полей и агрегатных функций

Использование агрегатных функций в запросе не требуется, если результатом запроса будут только группировочные поля:

06

К примеру, сделаем выборку всех вкусов, которые встречаются среди еды:

Как видите вкусы повторяются - давайте их сгруппируем:

Таким образом, мы сделали группировку только по группировочным полям (Вкус). Группируемые поля, а следовательно и агрегатные функции нам не понадобились.

Группировка без группировочных полей

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

12

К примеру, получим результаты агрегатных функций применительно к полю Калорийность без группировочных полей (то есть по всей таблице):

13

Группировка по нескольким полям

Группировочных (как впрочем и группируемых) полей может быть сколь угодно много. В запросе они перечисляются через запятую.


Пересечения строк и колонок образуют ячейки, в которых содержатся значения. Тип значения определяется типом значения колонки.

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

Создание таблицы значений

Как и большинство объектов встроенного языка, новая таблица значений может быть создана с помощью оператора Новый :

Колонки таблицы значений

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

Доступ к колонкам производится через свойство Колонки объекта ТаблицаЗначений . Для добавления новой колонки используется метод Добавить():

Для того, чтобы определить наличие колонки с нужным именем используется метод Найти():

Перебор колонок выполняется следующим образом:

Для удаления колонки используется метод Удалить():

Свойства колонки таблицы значений

Имя Тип Описание
Имя Строка символьный идентификатор колонки, по которому к ней можно обращаться из кода
Заголовок Строка строковое представление колонки на форме
ТипЗначения ОписаниеТипов свойство органичивает пространство доступных значений, которые можно указать в данной колонке
Ширина Число ширина колонки на форме (выражается в количестве символов)

Методы коллекции колонок таблицы значений

Вставить() Вставляет новую колонку в указанную позицию коллекции
Добавить() Добавляет новую колонку в конец коллекции
Количество() Возвращает количество колонок в коллекции
Найти() Ищет колонку в коллекции по имени
Очистить() Удаляет все колонки из коллекции
Сдвинуть() Сдвигает колонку влево или вправо
Удалить() Удаляет колонку из коллекции

Строки таблицы значений

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

Добавление и удаление строк

Для добавления новой строки используется метод Добавить() объекта ТаблицаЗначений . Метод возвращает объект СтрокаТаблицыЗначений , с которым доступны дальнейшие манипуляции:

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

Обратите внимание, что каждая СтрокаТаблицыЗначений ссылается на таблицу значений с помощью метода Владелец():

Для удаления строки используется метод Удалить() объекта ТаблицаЗначений . Строку можно удалить либо передав методу непосредственно строку, либо ее индекс:

Перебор строк таблицы значений

Для перебора строк удобнее всего использовать оператор цикла Для Каждого . В редких случаях оправдано применение цикла Для :

Поиск строк

Все методы таблицы значений:

Вставить() Вставляет строку на указанное место
ВыбратьСтроку() Позволяет интерактивно выбрать строку в диалоговом окне
ВыгрузитьКолонку() Выгружает значения ячеек указанной колонки в массив значений
Добавить() Добавлет новую строку в таблицу значений
ЗагрузитьКолонку() Загружает значения в ячейки указанной колонки из массива
ЗаполнитьЗначения() Заполняет ячейки указанных колонок определенным значением
Индекс() Возвращает индекс строки таблицы значений
Итог() Возвращает просуммированный итог по колонке таблицы значений
Количество() Возвращает количество строк в таблице значений
Найти() Выполняет поиск строки по значению
НайтиСтроки() Выполняет поиск строк по указанным параметрам
Очистить() Очищает строки таблицы значений
Получить() Возвращает строку по ее индексу
Свернуть() Выполняет сжатие строк и колонок таблицы значений
Сдвинуть() Сдвигает строку вверх или вниз по таблице
Скопировать() Создает новую таблицу значений копированием текущей
СкопироватьКолонки() Создает новую пустую таблицу значений путем копирования колонок текущей таблицы
Сортировать() Выполняет сортировку строк таблицы значений по указанным колонкам
Удалить() Удаляет строку таблицы значений

Иерархию свойств и типов значений, связанных с таблицей значений, схематически можно представить в виде дерева:

Читайте также: