Как исправить ошибку «Тип не может быть выбран в запросе» при передаче таблицы значений в запрос?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием IT и автоматизация бизнеса
← На главную

При разработке сложных механизмов анализа данных, таких как мониторинг Журнала регистрации или создание кастомных отчетов на основе внешних источников, программисты 1С часто сталкиваются с необходимостью передать Таблицу Значений (ТЗ) в запрос. Это стандартный прием: мы помещаем ТЗ во временную таблицу для дальнейшего соединения с данными информационной базы или для удобной фильтрации средствами SQL. Однако на этом пути нас подстерегает коварная ошибка: «Тип не может быть выбран в запросе». Особенно часто это происходит при работе с системными функциями, такими как ВыгрузитьЖурналРегистрации.

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

Выясняем причину ошибки

Проанализируем ситуацию: когда мы вызываем метод ВыгрузитьЖурналРегистрации, система заполняет объект ТаблицаЗначений. Проблема заключается в том, что колонки этой таблицы зачастую не имеют жесткой типизации. Платформа 1С позволяет колонкам ТЗ иметь тип Произвольный или содержать составные типы данных. Однако Менеджер временных таблиц, который отвечает за создание физических таблиц в СУБД (например, в MS SQL Server или PostgreSQL), требует четкого определения типов для каждой колонки.

Если в колонке Дата окажется неопределенное значение или если сама колонка в метаданных ТЗ не ограничена типом Дата, запрос выдаст ошибку. СУБД просто «не знает», какой длины и какого формата поле создавать в базе данных под ваши данные.

Решение 1: Предварительная типизация колонок таблицы значений

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

  1. Создаем пустую таблицу значений.
  2. Для каждой колонки определяем ОписаниеТипов.
  3. Добавляем колонки в таблицу, указывая созданные описания.
  4. Заполняем таблицу данными (через цикл или метод ЗагрузитьКолонку).

Посмотрим на пример кода, который решает проблему типизации колонки Дата и строковых полей:


// Определяем типы для колонок
МассивТиповДата = Новый Массив;
МассивТиповДата.Добавить(Тип("Дата"));
ОписаниеТипаДата = Новый ОписаниеТипов(МассивТиповДата);

МассивТиповСтрока = Новый Массив;
МассивТиповСтрока.Добавить(Тип("Строка"));
КвалификаторыСтроки = Новый КвалификаторыСтроки(200); // Ограничиваем длину
ОписаниеТипаСтрока = Новый ОписаниеТипов(МассивТиповСтрока, , КвалификаторыСтроки);

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

// После выгрузки из Журнала Регистрации переносим данные
// (Предположим, ЖР_Исходная — это результат ВыгрузитьЖурналРегистрации)
Для Каждого СтрокаЖР Из ЖР_Исходная Цикл
    ЗаполнитьЗначенияСвойств(ТЗ_ДляЗапроса.Добавить(), СтрокаЖР);
КонецЦикла;

Этот метод гарантирует, что Запрос.УстановитьПараметр("ТаблицаЖР", ТЗ_ДляЗапроса) отработает без ошибок, так как структура таблицы теперь полностью прозрачна для сервера базы данных.

Решение 2: Оптимизация отбора в Журнале регистрации

Иногда проблему можно решить еще на этапе получения данных. В исходном вопросе автор пытался отфильтровать событие через запрос, используя оператор ПОДОБНО (с маской %). Однако метод ВыгрузитьЖурналРегистрации сам по себе поддерживает мощные фильтры. Если мы передадим в структуру отбора массив нужных нам событий, то потребность в последующем запросе к ТЗ может вовсе отпасть.

Разберем, как правильно сформировать отбор по нескольким видам событий:


Отбор = Новый Структура;
Отбор.Вставить("ДатаНачала", ДатаНачала);
Отбор.Вставить("ДатаОкончания", ДатаОкончания);
Отбор.Вставить("Уровень", УровеньЖурналаРегистрации.Ошибка);

// Вместо фильтрации в запросе, передаем массив событий сразу
СписокСобытий = Новый Массив;
СписокСобытий.Добавить("СинхронизацияДанныхЧерезУниверсальныйФормат");
// Можно добавить и другие варианты, если нужно
Отбор.Вставить("Событие", СписокСобытий);

ЖР = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(ЖР, Отбор);

Проанализируем ситуацию: если мы сразу получаем отфильтрованную таблицу, нам не нужно помещать её в запрос только ради того, чтобы выполнить ГДЕ Событие = &Событие. Это экономит ресурсы сервера и избавляет от проблем с типами.

Решение 3: Использование метода НайтиСтроки

Если данных в журнале не десятки тысяч, а задача состоит в простом поиске, рассмотрим метод НайтиСтроки объекта ТаблицаЗначений. Важно помнить, что этот метод не поддерживает поиск по маске (символ %), но отлично работает с точными соответствиями. Если же нам нужен поиск подстроки (как ПОДОБНО в запросе), мы можем воспользоваться простым перебором с использованием функции СтрНайти.

Пример реализации без использования тяжеловесных запросов:


ТекстПоиска = "СинхронизацияДанныхЧерезУниверсальныйФормат";
МассивРезультатов = Новый Массив;

Для Каждого СтрокаЖР Из ЖР Цикл
    // Используем СтрНайти для имитации оператора ПОДОБНО
    Если СтрНайти(СтрокаЖР.Событие, ТекстПоиска) > 0 Тогда
        МассивРезультатов.Add(СтрокаЖР);
    КонецЕсли;
КонецЦикла;

Этот подход исключает ошибку «Тип не может быть выбран в запросе», так как мы вообще не обращаемся к механизму запросов платформы.

Особенности работы с данными Журнала регистрации в ERP

Рассмотрим специфику, упомянутую в обсуждении: автоматическая отправка ошибок синхронизации (например, между ERP и Розницей) в Telegram. Проблема автора заключалась в том, что сообщения об ошибках продолжали приходить даже после устранения причины, пока не была нажата кнопка «Синхронизировать».

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

Рекомендации по автоматизации этого процесса:

  1. Контроль периода: При анализе ЖР всегда ограничивайте выборку временем последнего успешного запуска или разумным интервалом (например, последние 15-30 минут).
  2. Проверка статуса: Вместо простого поиска текста ошибки в ЖР, попробуйте анализировать состояние узлов информационной базы через регистры сведений, отвечающие за синхронизацию (например, СостояниеОбменаДанными).
  3. Исключение дублей: Чтобы администратор не получал гору одинаковых уведомлений, можно кэшировать идентификаторы записей ЖР, о которых уже было отправлено сообщение.

Резюме

Мы выяснили, что ошибка типизации при загрузке ТЗ в запрос чаще всего вызвана отсутствием явного ОписаниеТипов в колонках таблицы. Для исправления ситуации следует либо типизировать таблицу вручную перед загрузкой, либо использовать штатные фильтры функции ВыгрузитьЖурналРегистрации. В случае с мониторингом ошибок обмена, наиболее эффективным решением является комбинирование узкого временного фильтра и поиска по массиву конкретных событий.

← На главную