gifts2017

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

Опубликовал Сергей Смирнов (Serginio) в раздел Программирование - Практика программирования

Я очень часто использую группировку данных по полю и  полям, как в восьмерке, так и в семерке. Это аналог запроса Итоги, но там строится дерево, а в большинстве случаев нужны "плоские данные". Да и делать запрос в большинстве случаев более накладный процесс, чем работа с ТЗ.
  Все достоинства такого подхода приведены на примере метода универсального списания по париям, а так же отбора строк в ТЗ по произвольному условию.
Для 7.7 еще отчеты сравнения двух ТЗ. Работая с различными базами для упрощения сравнения номенклатуры, или как аналог джойнов(join), сделал сравнение двух таблиц значений по нескольким полям. Пока группировки полей должны быть уникальны.
Часто приходится искать дубли, для универсального поиска есть ДублиВТзПоПолю и пример в Тест.ert.
///================ Группировка Данных ===============================================
Функция ПолучитьМассивСтрок(Тз,нач,кон)
    Массив= новый Массив(Кон-Нач+1);
    инд=0;
    Для сч=Нач по Кон Цикл
        Массив[инд]=Тз[сч];
        инд=инд+1;
    КонецЦикла;
    возврат Массив
КонецФункции

Функция глСгруппироватьТзПоПолю(Тз,Поле,ПоляСортировкиТзПоГруппе="") Экспорт
     перем Тип,Длина,Точность,ЕстьСпр,ЕстьДок;
     ЕстьСпр=0; ЕстьДок=0;

     Колонка=Тз.Колонки.Найти(Поле);
     // Для того что бы правильно сртировались элементы с одинаковыми представление
     // Сначала отсортируем по внутреннему значению
     //а после группирования по представлению по возрастанию
     Сравнение=Новый СравнениеЗначений;

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

         Для сч=0 По Тз.Количество()-1 Цикл
             строка=тз[сч];
               ТекЗаявка=Строка[Поле];

               Если (Сч=0) или ( Заявка<>ТекЗаявка) Тогда
                    Если НачСтр>-1 Тогда
                        ТекТз=Тз.Скопировать(ПолучитьМассивСтрок(Тз,НачСтр,сч-1));
                         СтрТзф.ТзПоГруппе=ТекТз;
                    КонецЕсли;

                   СтрТзф= ТзФ.Добавить();
                    Заявка=ТекЗаявка;
                   СтрТзф[Поле]=ТекЗаявка;
                    НачСтр=сч;
               КонецЕсли;
                       КонецЦикла;

          Если НачСтр>-1 Тогда
               ТекТз=Тз.Скопировать(ПолучитьМассивСтрок(Тз,НачСтр,Тз.Количество()-1));
               СтрТзф.ТзПоГруппе=ТекТз;
          КонецЕсли;
     КонецЕсли;
        Возврат ТзФ;
 КонецФункции

 Функция СравнитьПоля(Структ,Строка)
    Для каждого стр из Структ Цикл
        Если Стр.Значение<>Строка[Стр.Ключ] Тогда
            возврат ложь
        КонецЕсли;
    КонецЦикла;
        возврат истина
    КонецФункции

    Процедура ДобавитьПоля(Тз,ТзОриг,Поля) Экспорт
        если ПустаяСтрока(Поля) Тогда
            возврат
        КонецЕсли;

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

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

 Процедура ПроссумироватьПоля(Тз,ТзСтрок,МассивСуммируемыхПолей)
     Для Каждого Стр из МассивСуммируемыхПолей Цикл
        Тз[стр] = ТзСтрок.Итог(Стр);
     КонецЦикла;

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

Функция глСгруппироватьТзПоПолям(Тз,Поля,СуммируемыеПоля,ПоляСортировкиТзПоГруппе="") Экспорт
     перем Тип,Длина,Точность,ЕстьСпр,ЕстьДок;
     ЕстьСпр=0; ЕстьДок=0;

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

     // Для того что бы правильно сртировались элементы с одинаковыми представление
     // Сначала отсортируем по внутреннему значению
     //а после группирования по представлению по возрастанию
     Сравнение=Новый СравнениеЗначений;


   ПоляСортировки=Поля;
   Если не пустаяСтрока(ПоляСортировкиТзПоГруппе) Тогда
       ПоляСортировки=ПоляСортировки+","+ПоляСортировкиТзПоГруппе
   КонецЕсли;
   Тз.Сортировать(ПоляСортировки,Сравнение);

     ТзФ=новый ТаблицаЗначений;
      ДобавитьПоля(ТзФ,Тз,Поля);
      ДобавитьПоля(ТзФ,Тз,СуммируемыеПоля);

      ТзФ.Колонки.Добавить("ТзПоГруппе",Новый ОписаниеТипов("ТаблицаЗначений"));

     ТекСтр=0;
     Заявка=0;
     НачСтр=-1;
     СтрТзф="";
     Если Тз.Количество()>0 Тогда

         Для сч=0 По Тз.Количество()-1 Цикл
             строка=тз[сч];

               Если (Сч=0) или не СравнитьПоля(Структ,Строка) Тогда
                    Если НачСтр>-1 Тогда
                         ТекТз=Тз.Скопировать(ПолучитьМассивСтрок(Тз,НачСтр,сч-1));
                         СтрТзф.ТзПоГруппе=ТекТз;
                         ПроссумироватьПоля(СтрТзф,ТекТз,МассивСуммируемыхПолей);
                    КонецЕсли;

                   СтрТзф= ТзФ.Добавить();
                   Для каждого стр из Структ Цикл
                     Поле=Стр.Ключ;
                     Значение=Строка[поле];
                     Структ[Поле]=Значение;
                     СтрТзф[Поле]=Значение;

                   КонецЦикла;

                    НачСтр=сч;
               КонецЕсли;

          КонецЦикла;

          Если НачСтр>-1 Тогда
               ТекТз=Тз.Скопировать(ПолучитьМассивСтрок(Тз,НачСтр,Тз.Количество()-1));
               СтрТзф.ТзПоГруппе=ТекТз;
               ПроссумироватьПоля(СтрТзф,ТекТз,МассивСуммируемыхПолей);
          КонецЕсли;
     КонецЕсли;

     Возврат ТзФ;
 КонецФункции

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

Пример использования.

// Создаем запрос целью которого является соединение данных по документу и остатков ПартииТоваровНаСкладах
// Добавляем элемент для сортровки. Сначала идут элементы партий у которых совпадают Заказ и Заявка покупалеля, затем где поле заказ пустое
// Затем где заявкаи не совпадают. Можно их не учитывать


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

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

            // Здесь можно не указывать поля для сортровки, так как в глСгруппироватьТзПоПолям уже их указали
            ТзРезулт=ПолучитьТзСписаний(рез,Регистр,"КоличествоСписания","Количество","Стоимость",Отказ,"СортировакаПоЗаказу,МоментВремени");

            Если Отказ Тогда
                Предупреждение("Движения не запианы");
            Иначе
                ЗаписатьДвижения(ТзРезулт,ДокСсылка,Регистр)

            КонецЕсли;
         КонецПроцедуры

 Ну и на закуску

 

// Функция НайтиПоУсловию для отбора строк в ТЗ по различным условиям
//К сожалению в 1С нет ни лямбд ни делегатов
//но есть функция вычислить, которая выполняет текст

// Примеры использования
//тз=НайтиПоУсловию(тз,"Стр.Колонка1<20 и Стр.Колонка2>500");
//  или
//Список=ОбщегоНазначение.РазложитьСтрокуВМассивПодстрок("Иванов,Сидоров,Петров");

//Рез=НайтиПоУсловию(тз,"Список.Найти(стр.ФизЛицо)<>Неопределено");

//Или

//Рез=НайтиПоУсловию(тз,"Найти(Врег(стр.Значение),Врег(""акф""))>0");

//Рез=НайтиПоУсловию(тз,"Модуль.ФункцияСравнения(Стр,Список)",МассивСтруктур,ЭтотОбъект);

//То есть в модуле обработки должна быть функция
//  Функция ФункцияСравнения(стр,МассивСтруктур) Экспорт

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



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

Наименование Файл Версия Размер
ErtОбщегоНазначения.zip 1
.zip 65,86Kb
24.07.15
1
.zip 65,86Kb Скачать

См. также

Подписаться Добавить вознаграждение
В этой теме еще нет сообщений.