При разработке обработок в системе «1С:Предприятие 8» программисты часто сталкиваются с необходимостью передать данные, введенные пользователем на форме, во временную таблицу запроса. Одной из самых распространенных ошибок в этой ситуации является неправильная типизация колонок ТаблицыЗначений. Если типы колонок не определены явно, запрос может «ругаться» на несоответствие типов или выдавать непредсказуемые результаты при соединении таблиц. Давайте подробно разберем, как правильно подготовить таблицу значений и передать её в запрос на примере получения курсов валют.
Когда мы создаем объект ТаблицаЗначений программно, по умолчанию колонки не имеют строгого типа. Для платформы 1С и, что более важно, для СУБД (SQL Server, PostgreSQL и др.), такая таблица выглядит как набор неопределенных данных. При попытке поместить эту таблицу во временную таблицу запроса через МенеджерВременныхТаблиц, система пытается угадать типы данных, но это не всегда удается, особенно если в таблице нет строк или если данные в строках имеют составной тип.
Проанализируем ситуацию: автор сообщения пытался добавить колонку просто передав значение валюты в качестве второго параметра метода Добавить. Однако второй параметр метода Колонки.Добавить() ожидает объект ОписаниеТипов, а не саму ссылку на валюту. Рассмотрим, как сделать это правильно.
Для того чтобы запрос корректно обработал входящую таблицу, каждую колонку нужно типизировать с помощью объекта ОписаниеТипов. Это гарантирует, что СУБД будет знать точный размер и структуру полей. Рассмотрим пример кода:
// 1. Создаем объект Таблица Значений
ИсходныеДанные = Новый ТаблицаЗначений;
// 2. Формируем описание типов для Даты
// Рекомендуется указывать КвалификаторыДаты, чтобы исключить лишние части (время)
КвалификаторДаты = Новый КвалификаторыДаты(ЧастиДаты.Дата);
ОписаниеТипаДата = Новый ОписаниеТипов("Дата", , КвалификаторДаты);
ИсходныеДанные.Колонки.Добавить("Дата", ОписаниеТипаДата);
// 3. Формируем описание типов для Валюты
// Используем строковое имя метаданных или ссылку
ОписаниеТипаВалюта = Новый ОписаниеТипов("СправочникСсылка.Валюты");
ИсходныеДанные.Колонки.Добавить("Валюта", ОписаниеТипаВалюта);
Важный совет: Если вы хотите сделать код более устойчивым к изменениям в конфигураторе, лучше получать тип напрямую из метаданных. Вместо того чтобы писать строку "СправочникСсылка.Валюты", используйте конструкцию Метаданные.Справочники.Валюты.Тип. Это поможет избежать ошибок, если объект будет переименован.
После того как структура таблицы определена, её необходимо наполнить данными. Если данные берутся из реквизитов формы обработки, нужно помнить о контексте выполнения. В управляемых формах работа с ТаблицейЗначений возможна только на сервере. В обычных формах (толстый клиент) это можно делать непосредственно в модуле формы.
Рассмотрим, как добавить строку в нашу таблицу, используя данные из реквизитов формы (например, ДатаОтчета и ВыбраннаяВалюта):
// Добавляем новую строку в ТЗ
НоваяСтрока = ИсходныеДанные.Добавить();
// Заполняем данными из реквизитов (на форме или из объекта)
НоваяСтрока.Дата = Объект.ДатаОтчета;
НоваяСтрока.Валюта = Объект.Валюта; // Здесь 'Валюта' - это ссылка на справочник
Если вам нужно передать несколько значений (например, список валют), вы можете организовать цикл по списку значений или другой таблице на форме, заполняя ИсходныеДанные соответствующим образом.
Теперь, когда наша таблица типизирована и заполнена, мы можем передать её в запрос. В тексте запроса мы обращаемся к ней как к обычному параметру, но с использованием конструкции ВЫБРАТЬ ... ПОМЕСТИТЬ. Проанализируем пример сложного запроса для получения курсов валют на разные даты:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ИсходныеДанные.Дата КАК Дата,
| ИсходныеДанные.Валюта КАК Валюта
|ПОМЕСТИТЬ ВТ_ИсходныеДанные
|ИЗ
| &ИсходныеДанные КАК ИсходныеДанные
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ИсходныеДанные.Дата КАК Дата,
| ВТ_ИсходныеДанные.Валюта КАК Валюта,
| МАКСИМУМ(КурсыВалют.Период) КАК Период
|ПОМЕСТИТЬ ВТ_ДатыКурсов
|ИЗ
| ВТ_ИсходныеДанные КАК ВТ_ИсходныеДанные
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
| ПО ВТ_ИсходныеДанные.Валюта = КурсыВалют.Валюта
| И ВТ_ИсходныеДанные.Дата >= КурсыВалют.Период
|СГРУППИРОВАТЬ ПО
| ВТ_ИсходныеДанные.Дата,
| ВТ_ИсходныеДанные.Валюта
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ДатыКурсов.Дата КАК Дата,
| ВТ_ДатыКурсов.Валюта КАК Валюта,
| КурсыВалют.Курс КАК Курс,
| КурсыВалют.Кратность КАК Кратность
|ИЗ
| ВТ_ДатыКурсов КАК ВТ_ДатыКурсов
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
| ПО ВТ_ДатыКурсов.Валюта = КурсыВалют.Валюта
| И ВТ_ДатыКурсов.Период = КурсыВалют.Период";
Запрос.УстановитьПараметр("ИсходныеДанные", ИсходныеДанные);
РезультатЗапроса = Запрос.Выполнить();
Проанализируем несколько продвинутых техник, которые сделают ваш код более профессиональным и быстрым:
&ИсходныеДанные ожидается более 10-20 строк, обязательно добавьте индексацию. В тексте запроса после помещения во временную таблицу напишите: ИНДЕКСИРОВАТЬ ПО Валюта, Дата. Это позволит SQL-серверу мгновенно выполнять соединения.ВЫРАЗИТЬ(ИсходныеДанные.Валюта КАК Справочник.Валюты) КАК Валюта. Это предотвращает ошибки с "составными типами" и помогает оптимизатору запросов.Если ИсходныеДанные.Количество() > 0 Тогда.... Передача пустой таблицы в запрос с соединениями может привести к избыточной нагрузке или пустым временным таблицам, которые могут вызвать ошибки в последующих пакетах.Запрос и ТаблицаЗначений — это серверные объекты. Если вы работаете в Управляемом приложении, передавайте необходимые данные с формы (например, массив ссылок или структуру) на сервер, и уже там формируйте таблицу значений и выполняйте запрос.Рассмотрим, на чем чаще всего "спотыкаются" новички:
ДанныеФормыКоллекция не является ТаблицейЗначений. Его нужно сначала преобразовать методом РеквизитФормыВЗначение("ИмяРеквизита").ТаблицеЗначений должны строго совпадать с именами, которые вы используете в тексте запроса в секции &ИсходныеДанные КАК ИсходныеДанные. Регистр букв обычно не важен, но спецсимволы и пробелы недопустимы.Новый ОписаниеТипов("") или просто пропустите этот шаг, система назначит тип Произвольный, что почти гарантированно приведет к ошибке при попытке соединения с физической таблицей регистра сведений (например, с КурсыВалют).Следуя этим правилам, вы сможете эффективно использовать мощь языка запросов 1С для обработки любых данных, подготовленных на форме. Структурный подход к типизации данных — это залог стабильной работы конфигурации и отсутствия трудноуловимых ошибок в будущем.