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

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← К списку

Приветствуем вас! Сегодня мы с вами погрузимся в одну из распространенных проблем, с которой сталкиваются разработчики на платформе 1С:Предприятие – некорректная работа отбора в


ТаблицаЗначений
. Часто причина кроется в неочевидном несоответствии типов данных. Давайте вместе разберем эту ситуацию и найдем эффективные решения.

Выясняем причину: несоответствие типов данных

Представим типовую ситуацию: мы получаем данные из запроса в


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

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

Рассмотрим пример из практики, когда в запросе было выбрано поле, например,


РасчетыСКлиентами.ОбъектРасчетов
. Мы могли бы ожидать, что это поле является ссылкой на документ

ЗаказКлиента
, но на самом деле оно может оказаться ссылкой на

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

Как это выяснить? Мы можем использовать отладчик. Установите точку останова после выполнения запроса и выгрузки данных в


ТаблицаЗначений
. Затем в окне отладчика проанализируйте тип значения интересующего поля, например,

Выборка.ЗаказКлиента
(если вы так назвали поле в запросе) или непосредственно в строке

ТаблицаЗначений
. Для этого используйте функцию

ТипЗнч()
. Мы увидим, что вместо ожидаемого

ДокументСсылка.ЗаказКлиента
, там может быть, например,

СправочникСсылка.ОбъектыРасчетов
.

Корректировка запроса для получения нужного типа

Если мы выяснили, что поле в запросе возвращает не тот тип, который нам нужен для отбора, решение достаточно простое – необходимо скорректировать запрос. В нашем примере с


РасчетыСКлиентами.ОбъектРасчетов
, если мы хотим получить именно ссылку на документ

ЗаказКлиента
, нам нужно "дойти" до нужного объекта через его свойство

Объект
.

Давайте посмотрим на пример такого изменения в тексте запроса:


ВЫБРАТЬ
    РасчетыСКлиентами.ОбъектРасчетов.Объект КАК ЗаказКлиента,
    // Другие поля...
ИЗ
    РегистрНакопления.РасчетыСКлиентами КАК РасчетыСКлиентами
// Условия отбора...

В этом случае, добавив


.Объект
к

ОбъектРасчетов
, мы явно указываем платформе, что хотим получить сам объект, на который ссылается поле

ОбъектРасчетов
. Если

ОбъектРасчетов
является ссылкой на

Документ.ЗаказКлиента
, то

ОбъектРасчетов.Объект
вернет именно

ДокументСсылка.ЗаказКлиента
, что позволит корректно применять отбор.

Важность типизации полей в ТаблицеЗначений

Хотя колонки


ТаблицаЗначений
в 1С могут хранить значения произвольного типа, явное указание типа данных для колонок является хорошей практикой. Это особенно важно, если по этим колонкам вы планируете выполнять отбор или дальнейшую обработку. Если тип колонки не определен явно, платформа может неверно интерпретировать его или оставить как

Неопределено
, что затруднит корректное сравнение при отборе.

Мы можем добавить колонку с определенным типом, используя метод


Колонки.Добавить()
с параметром

ОписаниеТипов
. Рассмотрим пример:


// Создаем новую ТаблицуЗначений
ПеременнаяТЗ = Новый ТаблицаЗначений;

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

// Добавляем колонку "Сумма" числового типа
ПеременнаяТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));

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

Такой подход делает нашу


ТаблицаЗначений
более надежной и предсказуемой для дальнейшей работы.

Основные причины ошибок отбора, связанных с типами данных

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

  1. Несоответствие ссылочных типов: Как мы уже выяснили, это самая частая причина. Если в колонке хранится ссылка на один объект (например,
    
    СправочникСсылка.ОбъектыРасчетов
    
    ), а отбор производится по ссылке на другой объект (например,
    
    ДокументСсылка.ЗаказКлиента
    
    ), даже если они логически связаны, их внутренние типы платформой считаются разными, и сравнение не даст ожидаемого результата. Всегда проверяйте и явно указывайте конечный тип ссылки в запросах.
  2. Составные типы: Если колонка имеет составной тип (то есть может содержать значения разных типов, например,
    
    ДокументСсылка.ЗаказКлиента
    
    ИЛИ
    
    ДокументСсылка.РеализацияТоваровУслуг
    
    ), и вы пытаетесь отфильтровать ее по одному из этих типов, могут возникнуть сложности. В запросах это может проявляться ошибкой "Тип не может быть выбран в запросе", если не указан конкретный тип для поля составного типа. В таких случаях иногда приходится использовать функцию
    
    ВЫБОР КОГДА
    
    или приводить к нужному типу, если это возможно.
  3. Значения
    
    NULL
    
    :
    При работе с данными, где могут встречаться значения
    
    NULL
    
    (например, в результате левого соединения), сравнение с такими значениями может привести к неожиданным результатам, так как
    
    NULL
    
    не равен ничему, даже другому
    
    NULL
    
    . Рекомендуется использовать функцию
    
    ЕСТЬNULL()
    
    в запросах для явной обработки таких ситуаций, заменяя
    
    NULL
    
    на значение по умолчанию, которое можно сравнивать.

Различные способы отбора в ТаблицеЗначений

Теперь рассмотрим, какими методами мы можем осуществлять отбор в


ТаблицаЗначений
и когда какой из них предпочтителен:

  1. Метод

    
    НайтиСтроки()
    
    : Этот метод подходит для простого отбора по условию равенства. В него передается
    
    Структура
    
    , где ключи — это имена колонок, а значения — критерии отбора. Метод возвращает массив найденных строк.

    Посмотрим на пример:

    
    // Предположим, у нас есть ТаблицаЗначений ТЗ
    // с колонками "Контрагент", "Сумма", "Договор"
    
    // Создаем структуру для отбора
    СтруктураОтбора = Новый Структура;
    СтруктураОтбора.Вставить("Контрагент", СсылкаНаКонтрагента);
    СтруктураОтбора.Вставить("Договор", СсылкаНаДоговор);
    
    // Применяем отбор
    НайденныеСтроки = ТЗ.НайтиСтроки(СтруктураОтбора);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        Для Каждого СтрокаТЗ Из НайденныеСтроки Цикл
            Сообщить("Найденная строка: " + СтрокаТЗ.Сумма);
        КонецЦикла;
    Иначе
        Сообщить("Строки по заданным условиям не найдены.");
    КонецЕсли;
    
  2. Перебор и копирование: Для более сложных условий отбора (например, "больше", "меньше", "в иерархии", "содержит часть строки", "не равно") часто используется ручной перебор строк исходной

    
    ТаблицаЗначений
    
    и копирование подходящих строк в новую таблицу.

    Пример такого подхода:

    
    // Предположим, у нас есть ТаблицаЗначений ИсходнаяТЗ
    // с колонками "Дата", "Сумма", "Статус"
    
    ОтфильтрованнаяТЗ = Новый ТаблицаЗначений;
    Для Каждого Колонка Из ИсходнаяТЗ.Колонки Цикл
        ОтфильтрованнаяТЗ.Колонки.Добавить(Колонка.Имя, Колонка.ОписаниеТипов);
    КонецЦикла;
    
    Для Каждого СтрокаИсходнойТЗ Из ИсходнаяТЗ Цикл
        // Пример сложного условия отбора:
        // Сумма больше 1000 ИЛИ (Статус = "Оплачен" И Дата > НачалоМесяца(ТекущаяДата()))
        Если СтрокаИсходнойТЗ.Сумма > 1000 ИЛИ 
           (СтрокаИсходнойТЗ.Статус = "Оплачен" И СтрокаИсходнойТЗ.Дата > НачалоМесяца(ТекущаяДата())) Тогда
            ОтфильтрованнаяТЗ.Добавить().Заполнить(СтрокаИсходнойТЗ);
        КонецЕсли;
    КонецЦикла;
    
  3. Использование

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

    Давайте посмотрим, как это реализовать:

    
    // Предположим, у нас есть ТаблицаЗначений ИсходнаяТЗ
    // с колонками "Номенклатура", "Количество", "Склад"
    
    ПостроительЗапроса = Новый ПостроительЗапроса;
    ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(ИсходнаяТЗ);
    
    // Добавляем поля, которые хотим получить в результате
    ПостроительЗапроса.Поля.Добавить("Номенклатура");
    ПостроительЗапроса.Поля.Добавить("Количество");
    ПостроительЗапроса.Поля.Добавить("Склад");
    
    // Устанавливаем условие отбора
    ЭлементОтбора = ПостроительЗапроса.Отбор.Добавить("Номенклатура");
    ЭлементОтбора.ВидСравнения = ВидСравнения.ВИерархии;
    ЭлементОтбора.Значение = СсылкаНаГруппуНоменклатуры; // Отбор по группе номенклатуры
    ЭлементОтбора.Использование = Истина;
    
    ЭлементОтбора2 = ПостроительЗапроса.Отбор.Добавить("Количество");
    ЭлементОтбора2.ВидСравнения = ВидСравнения.Больше;
    ЭлементОтбора2.Значение = 10;
    ЭлементОтбора2.Использование = Истина;
    
    // Выполняем запрос и получаем отфильтрованную ТаблицуЗначений
    ОтфильтрованнаяТЗ = ПостроительЗапроса.Выполнить().Выгрузить();
    
  4. Свойство

    
    ОтборСтрок
    
    для элементов формы: Если
    
    ТаблицаЗначений
    
    отображается на форме через элемент "ТаблицаФормы" (особенно в управляемых формах), для нее можно использовать свойство
    
    ОтборСтрок
    
    расширения таблицы формы. Ему можно присвоить
    
    ФиксированнуюСтруктуру
    
    для установки интерактивного отбора по равенству.

    Пример использования в модуле формы:

    
    // Предположим, у нас есть элемент формы ТаблицаНаФорме, источником данных которого является ТЗ
    // и мы хотим отфильтровать ее по колонке "Статус" со значением "Активный"
    
    СтруктураОтбораФормы = Новый Структура("Статус", "Активный");
    Элементы.ТаблицаНаФорме.ОтборСтрок = Новый ФиксированнаяСтруктура(СтруктураОтбораФормы);
    

    Этот способ удобен для динамического изменения отбора, видимого пользователю.

Часто встречающиеся ошибки при работе с ТаблицамиЗначений и запросами

Помимо проблем с типами, мы можем столкнуться и с другими сложностями:

  1. "Ошибка отображения типов: Отсутствует отображение для типа '{http://v8.1c.ru/8.1/data/core}ValueTable'": Эта ошибка может возникать при попытке передачи

    
    ТаблицаЗначений
    
    с сервера на клиент в некоторых сценариях, когда платформа не может корректно сериализовать или десериализовать объект
    
    ValueTable
    
    . Обычно это связано с тем, что в
    
    ТаблицаЗначений
    
    содержатся объекты, которые не могут быть корректно переданы между контекстами (например, ссылки на формы, COM-объекты или объекты, которые не существуют на клиенте). Для решения проблемы необходимо убедиться, что все данные в
    
    ТаблицаЗначений
    
    являются сериализуемыми. Иногда помогает явное указание
    
    ОписаниеТипов
    
    для колонок.

  2. "Тип не может быть выбран в запросе": Помимо проблем с составными типами, эта ошибка также может указывать на несоответствие типов данных при сравнении или объединении полей в запросе (например, сравнение числового поля со строковым). Всегда проверяйте, что сравниваемые или объединяемые поля имеют совместимые типы. При необходимости используйте функции преобразования типов, такие как

    
    СТРОКА()
    
    ,
    
    ЧИСЛО()
    
    ,
    
    ДАТА()
    
    .

Для эффективной работы с отборами в


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

ТаблицаЗначений
в 1С.

← К списку