Как исправить ошибку сравнения типов в отчете по залежалому товару в 1С 7.7?

Программист Управленческий учет Торговля и дистрибуция
← На главную

При разработке отчетов в среде 1С:Предприятие 7.7 программисты часто сталкиваются с ситуацией, когда код работает корректно при одних настройках фильтров и выдает критическую ошибку при других. Одной из самых коварных ошибок является: "Операции сравнения на больше-меньше допустимы только над значениями совпадающих базовых типов". Рассмотрим подробнее, почему это происходит и как правильно организовать выборку данных по залежалому товару.

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

Проанализируем ситуацию. Ошибка возникает в строке Если ВыбДата > Д Тогда. В языке 1С 7.7 типизация переменных является мягкой, однако операции сравнения требуют, чтобы оба операнда принадлежали к одному базовому типу (число, строка или дата). Если в переменной ВыбДата хранится значение типа "Дата", а переменная Д по какой-то причине не была инициализирована (имеет тип Empty или Undefined), система не сможет выполнить сравнение и прервет работу программы.

Почему переменная Д оказывается пустой? Разберем по шагам логику отчета. Автор использует объект Периодический для получения даты последнего изменения цены (реквизит Прих_Цена). Если для конкретного товара в истории значений этого реквизита нет записей (например, после свертки базы или некорректного импорта остатков), цикл Пока Пер.ПолучитьЗначение() = 1 Цикл ни разу не выполнится. В результате переменная Д останется неопределенной.

Решение №1: Явная инициализация пустой даты

Самый простой и эффективный способ избежать ошибки — гарантировать, что переменная Д всегда будет иметь тип "Дата", даже если история значений пуста. Для этого перед началом перебора периодических значений нужно присвоить ей пустое значение соответствующего типа.

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


// Создаем объект для работы с типами
ПустаяДата = ПолучитьПустоеЗначение("Дата");

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

Решение №2: Оптимизация получения последнего значения

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

Посмотрим на пример использования метода ЗначениеНаДату или оптимизированного перебора:

  1. Использование метода ОбратныйПорядок: Если мы хотим получить самую свежую дату, можно включить обратный порядок выборки. Тогда первая же полученная запись будет последней по времени.
  2. Метод ПолучитьПоследнееЗначение: Вместо создания объекта Периодический можно обращаться напрямую к справочнику, если реквизит определен как периодический.

Проанализируем пример с оптимизацией цикла:


Пер.ИспользоватьОбъект("Прих_Цена", Тов);
// Устанавливаем обратный порядок, чтобы получить последнюю дату сразу
Пер.ОбратныйПорядок(1); 
Пер.ВыбратьЗначения();

Д = ПустаяДата;
Если Пер.ПолучитьЗначение() = 1 Тогда
    Д = Пер.ДатаЗнач;
КонецЕсли;
// Цикл больше не нужен, мы получили последнюю дату за одну итерацию

Важные замечания по производительности (Проблема N+1)

Рассмотрим ситуацию с точки зрения производительности. В представленном алгоритме объект Периодический создается один раз вне цикла, но методы ВыбратьЗначения() и ИспользоватьОбъект() вызываются внутри цикла по товарам. Это классическая проблема "N+1", когда для каждой строки отчета программа делает отдельный запрос к файловой базе данных (или SQL-серверу).

Рекомендация для больших баз:

Как проверить тип переменной программно?

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


// Тип 3 в 1С 7.7 соответствует типу "Дата"
Если (ТипЗначения(ВыбДата) = 3) И (ТипЗначения(Д) = 3) Тогда
    Если ВыбДата > Д Тогда
        // Логика вывода
    КонецЕсли;
Иначе
    Сообщить("Ошибка: Неверный тип данных для сравнения дат!");
КонецЕсли;

Подведем итог: главная причина ошибки крылась в отсутствии инициализации переменной. Всегда инициализируйте переменные, которые используются в условиях сравнения, особенно если они заполняются внутри циклов Пока ... Получить...() = 1. Использование ПолучитьПустоеЗначение("Дата") — это стандарт де-факто для обеспечения стабильности кода в 1С 7.7.

← На главную