При разработке отчетов или обработок в 1С:Предприятие мы часто сталкиваемся с необходимостью фильтрации данных или удаления дублей с помощью ключевого слова РАЗЛИЧНЫЕ (или DISTINCT в SQL-терминах). Однако, когда в выборку попадают поля типа Строка неограниченной длины или ХранилищеЗначений, платформа 1С блокирует выполнение запроса. Давайте разберем, почему это происходит и как правильно решить эту задачу, не нарушая архитектурных принципов системы.
Базы данных, на которых работает 1С (MS SQL Server, PostgreSQL, IBM DB2), имеют жесткие требования к индексации полей. Чтобы эффективно выполнять операцию поиска уникальных записей (РАЗЛИЧНЫЕ) или объединять наборы данных (ОБЪЕДИНИТЬ), СУБД должна уметь сравнивать значения в колонках. Поля типа Строка неограниченной длины или ХранилищеЗначений физически не могут быть проиндексированы стандартными способами, так как их размер не определен заранее.
Когда вы пытаетесь применить РАЗЛИЧНЫЕ к такому полю, сервер БД «понимает», что не может выполнить сравнение эффективно, и платформа 1С на этапе компиляции запроса выдает ошибку. Использование функций ПОДСТРОКА или ВЫРАЗИТЬ к ХранилищеЗначений также не поможет, так как эти объекты не являются строками — это сериализованные данные (картинки, двоичные данные или структуры).
Для исправления данной ошибки мы должны пересмотреть структуру запроса. Давайте рассмотрим пошагово, как правильно организовать получение данных.
Если в вашем запросе присутствует Левое соединение, которое порождает дубли, или если вам жизненно необходимо получить уникальный список документов, не тяните «тяжелое» поле сразу. Мы рекомендуем использовать Временные таблицы. Сначала сформируйте уникальный набор ссылок, а затем присоедините к ним дополнительные данные.
Посмотрим на пример правильного построения запроса:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Разрешения.Документ
ПОМЕСТИТЬ ВТ_УникальныеДокументы
ИЗ
РегистрСведений.Разрешения КАК Разрешения
ГДЕ
Разрешения.Период МЕЖДУ &ДатаНачала И &ДатаКонца;
ВЫБРАТЬ
Таможня.Номер,
Таможня.Дата,
Таможня.Склад,
Разрешения.ДанныеЗапроса
ИЗ
ВТ_УникальныеДокументы КАК ВТ
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Таможня КАК Таможня
ПО ВТ.Документ = Таможня.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Разрешения КАК Разрешения
ПО ВТ.Документ = Разрешения.Документ
Если поле ДанныеЗапроса является хранилищем, и вы планируете как-то преобразовывать его содержимое, лучше делать это после того, как запрос вернул результат в ВыборкаДетальныеЗаписи. Запрос должен возвращать только те данные, которые необходимы для фильтрации и связи таблиц.
Рассмотрим структуру обработки данных в цикле:
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Здесь мы можем безопасно извлечь данные из ХранилищаЗначений
// Используем метод Получить() для объекта ХранилищеЗначений
Данные = Выборка.ДанныеЗапроса.Получить();
НоваяСтрока = Объект.Инфо.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
НоваяСтрока.ДанныеЗапроса = Данные;
КонецЦикла;
Часто применение РАЗЛИЧНЫЕ — это лишь способ «замести следы» неправильно настроенных соединений. Если вы делаете соединение РегистрСведений с Документом, убедитесь, что в регистре нет нескольких записей с одинаковым документом, которые несут одну и ту же информацию. Если записи дублируются, попробуйте отфильтровать их на этапе обращения к регистру, выбрав только актуальную (например, последнюю по дате) запись.
РАЗЛИЧНЫЕ к полям ХранилищеЗначений или Строка неограниченной длины — это всегда приведет к ошибке.Временные таблицы для разделения этапа поиска уникальных записей и этапа извлечения «тяжелого» контента.ХранилищеЗначений, помните, что это не строка, и приводить его к СТРОКА(100) через ВЫРАЗИТЬ невозможно.Индексируемый реквизит или Хеш-сумму в том же регистре, что позволит делать быстрые отборы без участия основного хранилища.Анализируя ситуацию, мы пришли к выводу, что архитектурная чистота запроса важнее, чем попытка «втиснуть» всё в один пакет. Соблюдая эти правила, вы сможете избежать ошибок платформы и повысить производительность вашей конфигурации 1С.