Почему запрос по контрагенту в 1С возвращает пустой результат и как это исправить?

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

При разработке на платформе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда визуально правильный запрос не возвращает данных. Особенно часто это происходит при попытке выбрать документы (например, РеализацияТоваровУслуг) по конкретному контрагенту. Рассмотрим подробнее, почему так происходит, разберем причины возникновения ошибки и найдем способы её решения.

Анализ проблемы: типичная ошибка в коде

Представим стандартную ситуацию: нам нужно получить список проведенных реализаций за текущий год для определенного контрагента. Начинающий разработчик может написать следующий код:


Запрос = Новый Запрос("
|ВЫБРАТЬ
|   РеализацияТоваровУслуг.Номер Как Номер,
|   РеализацияТоваровУслуг.Дата Как Дата,
|   РеализацияТоваровУслуг.СуммаДокумента Как Сумма
|ИЗ
|   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
|   РеализацияТоваровУслуг.Контрагент = &Контрагент
|И
|   РеализацияТоваровУслуг.Дата МЕЖДУ &ДатаНач И &ДатаКон
|И
|   РеализацияТоваровУслуг.Проведен
|");

Запрос.УстановитьПараметр("ДатаНач", НачалоГода(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаКон", КонецГода(ТекущаяДата()));
Запрос.УстановитьПараметр("Контрагент", Контрагент);

Проанализируем ситуацию: если переменная Контрагент содержит не ссылку на элемент справочника, а просто строку (например, наименование "ООО Ромашка"), запрос всегда будет возвращать пустое значение. Выясним причину этого явления.

Причина №1: Несовпадение типов данных (Строка vs Ссылка)

В системе 1С поле Контрагент в документе имеет ссылочный тип (СправочникСсылка.Контрагенты). В базе данных SQL это поле представляет собой уникальный идентификатор (GUID). Когда мы передаем в параметр запроса строку, платформа пытается сравнить GUID со строкой. Поскольку это разные типы данных, условие РеализацияТоваровУслуг.Контрагент = &Контрагент никогда не будет выполнено (результат сравнения — Ложь).

Проверить, что именно содержится в переменной, можно с помощью функции ТипЗнч(). Посмотрим на пример диагностического сообщения:


Сообщить(Строка(ТипЗнч(Контрагент))); // Если выдаст "Строка", значит запрос не сработает

Решение проблемы: Получение ссылки

Чтобы запрос отработал корректно, нам нужно передать в параметр именно ссылку. Рассмотрим, как это сделать пошагово.

  1. Поиск по наименованию: Если у вас есть только строковое название, сначала нужно найти объект в справочнике.
  2. Проверка заполненности: Перед выполнением запроса обязательно убедитесь, что объект найден.
  3. Установка параметра: Передайте найденную ссылку в запрос.

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


// Пытаемся найти ссылку по имеющейся строке
КонтрагентСсылка = Справочники.Контрагенты.НайтиПоНаименованию(Контрагент, Истина);

Если ЗначениеЗаполнено(КонтрагентСсылка) Тогда
    Запрос = Новый Запрос;
    // ... текст запроса ...
    Запрос.Текст = "ВЫБРАТЬ ... ГДЕ РеализацияТоваровУслуг.Контрагент = &Контрагент ...";
    
    Запрос.УстановитьПараметр("Контрагент", КонтрагентСсылка);
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        // Обработка данных
    КонецЦикла;
Иначе
    Сообщить("Контрагент с наименованием '" + Контрагент + "' не найден в базе!");
КонецЕсли;

Важные замечания по оптимизации запроса

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

Избыточные условия (ПометкаУдаления и Проведен)

Часто в запросах можно встретить конструкцию:

ГДЕ Реализация.Проведен И НЕ Реализация.ПометкаУдаления

Важно понимать, что в 1С проведенный документ не может быть помечен на удаление одновременно. Как только пользователь помечает документ на удаление, система автоматически снимает его с проведения. Поэтому условия Реализация.Проведен более чем достаточно. Лишние проверки создают ненужную нагрузку на СУБД.

Производительность и обращение "через точку"

Иногда разработчики пытаются обойти проблему ссылок, обращаясь к наименованию прямо в запросе:

ГДЕ РеализацияТоваровУслуг.Контрагент.Наименование = &Контрагент

Рассмотрим, почему это плохая практика:

Регистры вместо документов

Для получения данных о продажах правильнее обращаться не к табличной части документов Документ.РеализацияТоваровУслуг, а к регистрам накопления (например, Продажи или ВыручкаИСебестоимостьПродаж). Документ может быть проведен, но по каким-то причинам не сформировать движения, либо движения могли быть изменены ручной операцией. Регистры показывают фактическое состояние учета и работают быстрее благодаря оптимизированным индексам.

Поиск по ИНН как более надежный вариант

Поиск по наименованию (НайтиПоНаименованию) таит в себе риски: в базе могут быть дубли (два "ООО Ромашка") или лишние пробелы/кавычки. Если есть возможность, лучше искать контрагента по уникальному идентификатору — ИНН.

КонтрагентСсылка = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ИскомыйИНН);

Подведем итог: всегда следите за типами данных, которые вы передаете в параметры запроса 1С. Использование ТипЗнч() — лучший способ быстрой отладки, а поиск ссылки перед выполнением запроса — залог получения корректного результата.

← На главную