При работе со сложными отчетами в конфигурациях на обычных формах (например, в «1С:Управление производственным предприятием», ред. 1.3) разработчики часто сталкиваются с наследием старого кода. Одной из типичных проблем является попытка отредактировать запрос отчета с помощью встроенного инструмента «Конструктор выходных форм», после чего система выдает критическую ошибку вида: {(6,2)}: Неверные параметры "ИменаЗатрат" >&ИменаЗатрат КАК Т. В этой статье мы подробно разберем, почему возникает данная ошибка, как устроены механизмы передачи внешних таблиц в запрос и как правильно оптимизировать код и логику работы с конструкторами в платформе «1С:Предприятие».
Для того чтобы понять природу проблемы, проанализируем поведение платформы. Инструмент «Конструктор выходных форм» — это устаревший визуальный мастер (так называемая «некротехнология» времен платформ 8.0 и 8.1), предназначенный для первоначального проектирования простых отчетов на базе объекта ПостроительОтчета. Этот конструктор ориентирован исключительно на работу с простыми, однокомпонентными запросами, которые выбирают данные напрямую из физических таблиц базы данных (справочников, документов или регистров).
Когда предыдущий программист дорабатывал отчет, он превратил исходный простой запрос в пакетный запрос и добавил в него использование внешней таблицы значений в качестве параметра:
ВЫБРАТЬ Т.Затрата, Т.Имя ПОМЕСТИТЬ ИменаЗатрат ИЗ &ИменаЗатрат КАК Т ;
При попытке открыть такой запрос через «Конструктор выходных форм» происходит следующее:
ИЗ он натыкается на параметр &ИменаЗатрат.Важное правило разработки: «Конструктор выходных форм» категорически не умеет работать с пакетными запросами, временными таблицами и параметрами, содержащими таблицы значений. Этот инструмент предназначен только для генерации первоначального шаблона кода и макета. Любое ручное вмешательство в запрос (особенно превращение его в пакетный) навсегда «закрывает» возможность использования этого конструктора.
Разберем по шагам, как нужно поступать в подобных ситуациях. Для редактирования запросов мы должны использовать исключительно стандартный «Конструктор запроса», который полностью поддерживает работу со всеми современными конструкциями языка запросов 1С.
Если нам необходимо внести изменения в запрос визуально, но конструктор запроса ругается на параметр-таблицу или временную таблицу, выполним следующие действия:
ИменаЗатрат и позволял связывать ее поля с другими таблицами пакета в визуальном режиме, перейдем на вкладку «Дополнительно».ИменаЗатрат.Затрата (тип: Строка) и Имя (тип: Строка).Платформа «1С:Предприятие» накладывает жесткие требования на передачу внешних таблиц значений в качестве параметров запроса. Если передать неподготовленную таблицу значений, система выдаст ошибку на этапе исполнения кода.
Посмотрим на пример правильной подготовки таблицы значений во встроенном языке, который решает проблему типизации:
// 1. Создаем объект ТаблицаЗначений
ИменаЗатрат = Новый ТаблицаЗначений;
// 2. Создаем описание типов для колонок таблицы.
// Запрос должен четко знать типы полей, иначе возникнет ошибка выполнения!
КС = Новый КвалификаторыСтроки(150);
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Строка"));
ОписаниеТиповС = Новый ОписаниеТипов(МассивТипов, , КС);
// 3. Добавляем колонки с обязательным указанием типов данных
ИменаЗатрат.Колонки.Добавить("Затрата", ОписаниеТиповС);
ИменаЗатрат.Колонки.Добавить("Имя", ОписаниеТиповС);
// 4. Заполняем таблицу значений данными (например, из справочника Статьи Затрат)
Выборка = Справочники.СтатьиЗатрат.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.ЭтоГруппа Тогда
Продолжить;
КонецЕсли;
НоваяСтрока = ИменаЗатрат.Добавить();
НоваяСтрока.Затрата = СокрЛП(Выборка.Наименование);
// Выделяем имя затраты до скобки, если она присутствует в наименовании
Поз = Найти(НоваяСтрока.Затрата, "(");
Если Поз = 0 Тогда
НоваяСтрока.Имя = НоваяСтрока.Затрата;
Иначе
НоваяСтрока.Имя = Лев(НоваяСтрока.Затрата, Поз - 1);
КонецЕсли;
КонецЦикла;
// 5. Устанавливаем подготовленную таблицу значений в параметр запроса
Запрос.УстановитьПараметр("ИменаЗатрат", ИменаЗатрат);
Обратите внимание: Если вы создадите колонку таблицы значений методом ИменаЗатрат.Колонки.Добавить("Затрата") (без указания второго параметра — объекта ОписаниеТипов), колонка получит тип Неопределено. При передаче такой таблицы в запрос платформа сгенерирует ошибку несовместимости типов, так как СУБД не сможет сопоставить колонку с физическими типами данных SQL.
Проанализируем структуру исходного запроса из первого сообщения. Предыдущий программист использовал каскадную вложенность операторов ВЫБОР КОГДА ... ИНАЧЕ ВЫБОР КОГДА .... Такая запись существенно затрудняет чтение кода, увеличивает вероятность синтаксической ошибки (например, легко запутаться в количестве закрывающих операторов КОНЕЦ) и может негативно влиять на производительность парсера запросов.
Рассмотрим структуру исходного неоптимального фрагмента:
ВЫБОР КОГДА ХозрасчетныйОбороты.Счет.Родитель.Код = "02" ТОГДА
"6. Амортизация"
ИНАЧЕ
ВЫБОР КОГДА ХозрасчетныйОбороты.Счет = &Счет70 ТОГДА
"8. Заработная плата"
ИНАЧЕ
ВЫБОР КОГДА ХозрасчетныйОбороты.КорСчет В (&МатЗатраты) ТОГДА
"1. Материальные затраты"
ИНАЧЕ
// И так далее...
КОНЕЦ
КОНЕЦ
КОНЕЦ
В языке запросов «1С» оператор ВЫБОР поддерживает плоскую структуру условий. Мы можем перечислить все условия последовательно через ключевое слово КОГДА внутри одной конструкции. Перепишем этот фрагмент в оптимизированном и легко читаемом виде:
ВЫБОР
КОГДА ХозрасчетныйОбороты.Счет.Родитель.Код = "02" ТОГДА "6. Амортизация"
КОГДА ХозрасчетныйОбороты.Счет = &Счет70 ТОГДА "8. Заработная плата"
КОГДА ХозрасчетныйОбороты.КорСчет В (&МатЗатраты) ТОГДА "1. Материальные затраты"
КОГДА ХозрасчетныйОбороты.КорСчет В (&Услуги) ТОГДА "2. Услуги"
КОГДА ХозрасчетныйОбороты.КорСчет В (&Кап) ТОГДА "3. Капитальные вложения"
КОГДА ХозрасчетныйОбороты.КорСчет В (&РасхБп) ТОГДА "4. Расходы будущих периодов"
КОГДА ХозрасчетныйОбороты.КорСчет В (&ЗаПрибыль) ТОГДА "5. Расходы за счет прибыли"
ИНАЧЕ "!!!!!"
КОНЕЦ КАК Группа
Такой подход делает код лаконичным, снижает риск совершить синтаксическую ошибку и значительно упрощает отладку запроса.
В сообщении №10 автор интересуется возможностью вывода документов-регистраторов непосредственно в макет этого отчета. Разберем, как это реализовать.
Для того чтобы вывести документы, по которым сформировались обороты, нам необходимо модифицировать исходный запрос, так как в нем используется периодичность Месяц для виртуальной таблицы оборотов регистра бухгалтерии:
РегистрБухгалтерии.Хозрасчетный.Обороты(&ДН, &ДК, Месяц, ...)
При периодичности Месяц платформа группирует данные по месяцам, и получить конкретный документ (регистратор) напрямую невозможно. Чтобы решить эту задачу, нам необходимо:
Регистратор:
ИЗ РегистрБухгалтерии.Хозрасчетный.Обороты(&ДН, &ДК, Регистратор, Счет В ИЕРАРХИИ (&Счет60), , &УсловиеПоКлиенту, , ) КАК ХозрасчетныйОбороты
ХозрасчетныйОбороты.Регистратор в список выбираемых полей первого пакета запроса (таблица тмп) и включить его в секцию СГРУППИРОВАТЬ ПО.Регистратор через все последующие временные таблицы пакета запроса (Ит, Итг, ИтоговаяТаблица) до самого последнего итогового запроса.Регистратор в список полей выборки и в группировки ИТОГИ ... ПО (например, добавив уровень группировки по регистратору после детальной расшифровки).Рекомендация по развитию архитектуры: Если отчет требует сложной иерархической структуры, вывода регистраторов, динамической настройки группировок пользователем и использования внешних таблиц значений — откажитесь от ручного построения макетов и старого построителя отчетов. Переведите данный отчет на Систему компоновки данных (СКД). СКД без проблем принимает таблицы значений через внешние наборы данных, автоматически генерирует сложные макеты и позволяет выводить детальные записи (документы) одной галочкой в пользовательских настройках.