Книга знаний

1С:Предприятие / v8 / Приемы программирования / Запросы

v8: Хитрая технология виртуальных таблиц для запросов

В 1С имеются виртуальные таблицы, которые очень удобно использовать. Часто хочется иметь и свои виртуальные таблицы. Пример показывает, как можно реализовать такие таблицы.Автор статьи: Гений 1С
Последняя редакция №1 от 04.04.08
URL: http://kb.mista.ru/article.php?id=652

Ключевые слова: запросы, виртуальные таблицы,


Вообще видимо с выходом компоновки данных для 81 технология станет неактуальной, но для 80 все еще актуальна.

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

Может кому и пригодится, юзайте.


Код для вызова виртуальной таблицы за период Дата1-Дата2:
        ВыбОтбор=Новый Структура("Договор", ВыбДоговоры);
        ПП=Новый Структура();
        ПП.Вставить("Отбор", ВыбОтбор);
        М=Новый Массив();
        М.Добавить("Договор");
        М.Добавить("СуммаФактОплата");
        М.Добавить("СуммаФактПоставка");
        М.Добавить("СуммаНДСФактОплата");
        М.Добавить("СуммаНДСФактПоставка");
        ПП.Вставить("Поля", М);
        ПП.Вставить("Дата1", Дата1);
        ПП.Вставить("Дата2", Дата2);
        ТЗСуммы=гмВиртуальнаяТаблицаФактическаяПоставкаОплата(ПП);



Функции, описывающи виртуальную таблицу:

//Получаем виртуальную таблицу фактической оплаты или поставки
Функция гмВиртуальнаяТаблицаФактическаяПоставкаОплата(П) Экспорт
    обПодготовитьВиртуальнуюТаблицу(П);
    
    //По факту
    П.Текст=                  
    "ВЫБРАТЬ
    |    &Поле_Договор_ КАК Договор,
    |    &Поле_Статья_ КАК Статья,
    |    &Поле_ОП_ КАК ОП,
    |    &Поле_СуммаФактОплата_ КАК СуммаФактОплата,
    |    &Поле_СуммаНДСФактОплата_ КАК СуммаНДСФактОплата,
    |    &Поле_СуммаФактПоставка_ КАК СуммаФактПоставка,
    |    &Поле_СуммаНДСФактПоставка_ КАК СуммаНДСФактПоставка
    |ИЗ
    |    РегистрБухгалтерии.Бюджетирование.Обороты(
    |        &Дата1,
    |        &Дата2,
    |        ,
    |        Счет В ИЕРАРХИИ (&СчетаДеньги)
    |            ИЛИ Счет В ИЕРАРХИИ (&СчетаПрибыль),
    |        ,
    |        ВариантБюджета = &ВыбБюджет
    |            И &Условие_Договор_,
    |        КорСчет В ИЕРАРХИИ (&СчетаКонтрагенты),
    |        ) КАК Т";
    
    М=Новый Массив();
    М.Добавить(ПланыСчетов.Бюджетирование.ДенежныеСредства); //51
    П.Параметры.Вставить("СчетаДеньги",  М);
    
    М=Новый Массив();
    //М.Добавить(ПланыСчетов.Бюджетирование.РасчетыСКонтрагентами); //76.*
    М.Добавить(ПланыСчетов.Бюджетирование.Покупатели); //62.*
    М.Добавить(ПланыСчетов.Бюджетирование.РасчетыСПоставщиками); //60.1
    П.Параметры.Вставить("СчетаКонтрагенты",  обПолучитьВложенныеЭлементы("ПланСчетов.Бюджетирование", М));
    
    М=Новый Массив();
    М.Добавить(ПланыСчетов.Бюджетирование.Покупатели); //62.*
    П.Параметры.Вставить("СчетаПокупатели",  обПолучитьВложенныеЭлементы("ПланСчетов.Бюджетирование", М));
    
    М=Новый Массив();
    М.Добавить(ПланыСчетов.Бюджетирование.РасчетыСПоставщиками); //60.1
    П.Параметры.Вставить("СчетаПоставщики",  обПолучитьВложенныеЭлементы("ПланСчетов.Бюджетирование", М));
    
    
    М=Новый Массив();
    М.Добавить(ПланыСчетов.Бюджетирование.ДоходыРасходы); //90
    М.Добавить(ПланыСчетов.Бюджетирование.ВнеоборотныеАктивы); //01
    Сч001=ПланыСчетов.Бюджетирование.НайтиПоКоду("001");
    Если НЕ ЗначениеНеЗаполнено(Сч001) Тогда
        М.Добавить(Сч001);
    КонецЕсли;
    П.Параметры.Вставить("СчетаПрибыль",  обПолучитьВложенныеЭлементы("ПланСчетов.Бюджетирование", М));
    
    П.Параметры.Вставить("ВыбБюджет",  Справочники.ВариантыБюджета.ИсполнениеБюджетаВторогоУровня); //ФАКТ
    
    
    П.Параметры.Вставить("ПустоеЗначение_ЗаявкаНаЗакупку_", Документы.ЗаявкаНаЗакупку.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_Протокол_", Документы.Протокол.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_Договор_", Документы.КарточкаДоговора.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_Спецификация_", Документы.Спецификация.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_Статья_", Справочники.КБК.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_Лот_", Справочники.НаименованияЗакупаемойПродукции.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_ЗаявкаНаЗакупку_", Документы.ЗаявкаНаЗакупку.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_Мероприятие_", Справочники.Мероприятия.ПустаяСсылка());
    П.Параметры.Вставить("ПустоеЗначение_ОП_", Справочники.Подразделения.ПустаяСсылка());
    
    
    //Определения полей
    П.Дефиниции.Вставить("Поле_Договор_", "ЕстьNULL(ВЫРАЗИТЬ(Субконто3 КАК Документ.Спецификация).ДоговорОснование, &ПустоеЗначение_Договор_)");
    П.Дефиниции.Вставить("Поле_Статья_", "ЕстьNULL(ВЫРАЗИТЬ(Субконто2 КАК Справочник.СтатьиБюджета), &ПустоеЗначение_Статья_)");
    П.Дефиниции.Вставить("Поле_ОП_", "ЕстьNULL(ВЫРАЗИТЬ(Субконто1 КАК Справочник.Подразделения), &ПустоеЗначение_ОП_)");
    
    //Определения пустых полей
    П.Дефиниции.Вставить("ПустоеПоле_Договор_", "&ПустоеЗначение_Договор_");
    П.Дефиниции.Вставить("ПустоеПоле_Статья_", "&ПустоеЗначение_Статья_");
    П.Дефиниции.Вставить("ПустоеПоле_ОП_", "&ПустоеЗначение_ОП_");
    П.Дефиниции.Вставить("ПустоеПоле_СуммаФактОплата_", "0");
    П.Дефиниции.Вставить("ПустоеПоле_СуммаФактПоставка_", "0");
    П.Дефиниции.Вставить("ПустоеПоле_СуммаНДСФактОплата_", "0");
    П.Дефиниции.Вставить("ПустоеПоле_СуммаНДСФактПоставка_", "0");
    
    //Определение условий
    П.Дефиниции.Вставить("Условие_Договор_", "(&Поле_Договор_ В (&Отбор_Договор_))");
    
    //Вычисления
    П.Дефиниции.Вставить("Выражение_ЗнакОплаты_", 
    "
    |    ВЫБОР
    |            КОГДА Т.Счет В (&СчетаДеньги)
    |                    И Т.КорСчет В (&СчетаПокупатели)
    |                ТОГДА 1
    |            КОГДА Т.Счет В (&СчетаДеньги)
    |                    И Т.КорСчет В (&СчетаПоставщики)
    |                ТОГДА -1
    |            ИНАЧЕ 0
    |        КОНЕЦ
    |");
    П.Дефиниции.Вставить("Выражение_ЗнакПоставки_", 
    "
    |    ВЫБОР
    |            КОГДА Т.Счет В (&СчетаПрибыль)
    |                    И Т.КорСчет В (&СчетаПокупатели)
    |                ТОГДА -1
    |            КОГДА Т.Счет В (&СчетаПрибыль)
    |                    И Т.КорСчет В (&СчетаПоставщики)
    |                ТОГДА 1
    |            ИНАЧЕ 0
    |        КОНЕЦ
    |");
    П.Дефиниции.Вставить("Поле_СуммаФактОплата_", "&Выражение_ЗнакОплаты_*Т.СуммаОборот");
    П.Дефиниции.Вставить("Поле_СуммаФактПоставка_", "&Выражение_ЗнакПоставки_*Т.СуммаОборот");
    П.Дефиниции.Вставить("Поле_СуммаНДСФактОплата_", "&Выражение_ЗнакОплаты_*Т.СуммаНДСОборот");
    П.Дефиниции.Вставить("Поле_СуммаНДСФактПоставка_", "&Выражение_ЗнакПоставки_*Т.СуммаНДСОборот");
    
    Возврат обРассчитатьВиртуальнуюТаблицу(П);
    
КонецФункции


//В структуре П виртуальной таблицы должны быть свойтсва:
//    Отбор - структура отбора
//    Поля - массив полей
Функция обПодготовитьВиртуальнуюТаблицу(П, Пустая=ложь)
    Если НЕ П.Свойство("Дефиниции") ИЛИ Пустая Тогда
        П.Вставить("Дефиниции", Новый Структура());
    КонецЕсли;
    Если НЕ П.Свойство("Текст") ИЛИ Пустая  Тогда
        П.Вставить("Текст", "");
    КонецЕсли;
    Если НЕ П.Свойство("КонечныйТекст") ИЛИ Пустая  Тогда
        П.Вставить("КонечныйТекст", "");
    КонецЕсли;
    Если НЕ П.Свойство("КоличествоЗаменТекстаЗапроса") ИЛИ Пустая  Тогда
        П.Вставить("КоличествоЗаменТекстаЗапроса", 0);
    КонецЕсли;
    Если НЕ П.Свойство("Параметры") ИЛИ Пустая  Тогда
        П.Вставить("Параметры", Новый Структура());
    КонецЕсли;
    Если НЕ П.Свойство("ТаблицаЗаменыДефиниций") ИЛИ Пустая  Тогда
        П.Вставить("ТаблицаЗаменыДефиниций", Новый Структура());
    КонецЕсли;
    Если НЕ П.Свойство("АвтоСписокПолей") ИЛИ Пустая  Тогда
        П.Вставить("АвтоСписокПолей", истина);
    КонецЕсли;
КонецФункции

Функция обРассчитатьВиртуальнуюТаблицу(П)
    
    П.Текст=СтрЗаменить(П.Текст, "&Договор", "ЕстьNULL(ВЫРАЗИТЬ(Субконто3 КАК Документ.Спецификация).ДоговорОснование, &ПустойДоговор)");
    
    //Смотрим, есть ли в параметрах Дата1 И Дата2
    Если П.Свойство("Дата1") Тогда
        П.Параметры.Вставить("Дата1", П.Дата1);
    Иначе
        Если НЕ П.Дефиниции.Свойство("Дата1") Тогда
            П.Дефиниции.Вставить("Дата1", "");
        КонецЕсли;
    КонецЕсли;
    Если П.Свойство("Дата2") Тогда
        П.Параметры.Вставить("Дата2", П.Дата2);
    Иначе
        Если НЕ П.Дефиниции.Свойство("Дата2") Тогда
            П.Дефиниции.Вставить("Дата2", "");
        КонецЕсли;
    КонецЕсли;
    
    //Убираем ненужные поля
    Если П.АвтоСписокПолей Тогда
        НаличныеПоля=Новый Структура();
        //ПоляКЗамене=Новый Массив;
        Для Каждого Эл Из П.Поля Цикл
            НаличныеПоля.Вставить("Поле_"+Эл+"_");
        КонецЦикла;
        Для Каждого КЗ Из П.Дефиниции Цикл
            //Проверяем, действительно ли это поле
            Если Найти(КЗ.Ключ, "Поле_")=1 И НЕ НаличныеПоля.Свойство(КЗ.Ключ) Тогда
                П.Дефиниции.Вставить(КЗ.Ключ, "&ПустоеПоле_"+Сред(КЗ.Ключ, 6));
            КонецЕсли;
        КонецЦикла;
        //Для Каждого Эл ИЗ ПоляКЗамене Цикл
        //    П.Дефиниции.Вставить(Эл, "&ПустоеПоле_"+Сред(Эл, 6));
        //КонецЦикла;
    КонецЕсли;
    
    
    //Делаем замены, пока не исчерпаем
    //Вообще неплохо бы отсортировать дефиниции по длине строки, чтобы сначала заменять самые большие
    //Пример: &ТекстДоговора и &ТекстДоговора1, сначала надо заменять &ТекстДоговора1
    ТЗ=Новый ТаблицаЗначений();
    ТЗ.Колонки.Добавить("Имя");
    ТЗ.Колонки.Добавить("Длина");
    ТЗ.Колонки.Добавить("Замена");
    Для Каждого Эл Из П.Дефиниции Цикл
        НСтр=ТЗ.Добавить();
        НСтр.Имя=Эл.Ключ;
        НСтр.Замена=Эл.Значение;
        НСтр.Длина=СтрДлина(Эл.Ключ);
    КонецЦикла;
    ТЗ.Сортировать("Длина Убыв");
    П.ТаблицаЗаменыДефиниций=ТЗ;
    
    
    П.КоличествоЗаменТекстаЗапроса=0;
    Пока Истина Цикл
        ТекТекст=П.Текст;
        Для Каждого Стр Из П.ТаблицаЗаменыДефиниций Цикл
            П.Текст=СтрЗаменить(П.Текст, "&"+Стр.Имя, Стр.Замена);
        КонецЦикла;
        П.КоличествоЗаменТекстаЗапроса=П.КоличествоЗаменТекстаЗапроса+1;
        Если ТекТекст=П.Текст Тогда
            Прервать;
        КонецЕсли;
        //Избегаем зацикливания
        Если П.КоличествоЗаменТекстаЗапроса>1000 Тогда
            Сообщить("Обнаружено зацикливание текста запроса!");
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Запрос=Новый Запрос(П.Текст);
    Для Каждого Эл ИЗ П.Параметры Цикл
        Запрос.УстановитьПараметр(Эл.Ключ, Эл.Значение);
    КонецЦикла;
    Для Каждого Эл ИЗ П.Отбор Цикл
        Запрос.УстановитьПараметр("Отбор_"+Эл.Ключ+"_", Эл.Значение);
    КонецЦикла;
        
    ТЗ=Запрос.Выполнить().Выгрузить();
    Возврат ТЗ;
КонецФункции


Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика