При разработке на платформе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда визуально правильный запрос не возвращает данных. Особенно часто это происходит при попытке выбрать документы (например, РеализацияТоваровУслуг) по конкретному контрагенту. Рассмотрим подробнее, почему так происходит, разберем причины возникновения ошибки и найдем способы её решения.
Представим стандартную ситуацию: нам нужно получить список проведенных реализаций за текущий год для определенного контрагента. Начинающий разработчик может написать следующий код:
Запрос = Новый Запрос("
|ВЫБРАТЬ
| РеализацияТоваровУслуг.Номер Как Номер,
| РеализацияТоваровУслуг.Дата Как Дата,
| РеализацияТоваровУслуг.СуммаДокумента Как Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Контрагент = &Контрагент
|И
| РеализацияТоваровУслуг.Дата МЕЖДУ &ДатаНач И &ДатаКон
|И
| РеализацияТоваровУслуг.Проведен
|");
Запрос.УстановитьПараметр("ДатаНач", НачалоГода(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаКон", КонецГода(ТекущаяДата()));
Запрос.УстановитьПараметр("Контрагент", Контрагент);
Проанализируем ситуацию: если переменная Контрагент содержит не ссылку на элемент справочника, а просто строку (например, наименование "ООО Ромашка"), запрос всегда будет возвращать пустое значение. Выясним причину этого явления.
В системе 1С поле Контрагент в документе имеет ссылочный тип (СправочникСсылка.Контрагенты). В базе данных SQL это поле представляет собой уникальный идентификатор (GUID). Когда мы передаем в параметр запроса строку, платформа пытается сравнить GUID со строкой. Поскольку это разные типы данных, условие РеализацияТоваровУслуг.Контрагент = &Контрагент никогда не будет выполнено (результат сравнения — Ложь).
Проверить, что именно содержится в переменной, можно с помощью функции ТипЗнч(). Посмотрим на пример диагностического сообщения:
Сообщить(Строка(ТипЗнч(Контрагент))); // Если выдаст "Строка", значит запрос не сработает
Чтобы запрос отработал корректно, нам нужно передать в параметр именно ссылку. Рассмотрим, как это сделать пошагово.
Разберем исправленный пример кода:
// Пытаемся найти ссылку по имеющейся строке
КонтрагентСсылка = Справочники.Контрагенты.НайтиПоНаименованию(Контрагент, Истина);
Если ЗначениеЗаполнено(КонтрагентСсылка) Тогда
Запрос = Новый Запрос;
// ... текст запроса ...
Запрос.Текст = "ВЫБРАТЬ ... ГДЕ РеализацияТоваровУслуг.Контрагент = &Контрагент ...";
Запрос.УстановитьПараметр("Контрагент", КонтрагентСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
КонецЦикла;
Иначе
Сообщить("Контрагент с наименованием '" + Контрагент + "' не найден в базе!");
КонецЕсли;
Проанализируем еще несколько важных моментов, упомянутых опытными разработчиками, которые помогут сделать ваш код профессиональнее.
Часто в запросах можно встретить конструкцию:
ГДЕ Реализация.Проведен И НЕ Реализация.ПометкаУдаления
Важно понимать, что в 1С проведенный документ не может быть помечен на удаление одновременно. Как только пользователь помечает документ на удаление, система автоматически снимает его с проведения. Поэтому условия Реализация.Проведен более чем достаточно. Лишние проверки создают ненужную нагрузку на СУБД.
Иногда разработчики пытаются обойти проблему ссылок, обращаясь к наименованию прямо в запросе:
ГДЕ РеализацияТоваровУслуг.Контрагент.Наименование = &Контрагент
Рассмотрим, почему это плохая практика:
Для получения данных о продажах правильнее обращаться не к табличной части документов Документ.РеализацияТоваровУслуг, а к регистрам накопления (например, Продажи или ВыручкаИСебестоимостьПродаж). Документ может быть проведен, но по каким-то причинам не сформировать движения, либо движения могли быть изменены ручной операцией. Регистры показывают фактическое состояние учета и работают быстрее благодаря оптимизированным индексам.
Поиск по наименованию (НайтиПоНаименованию) таит в себе риски: в базе могут быть дубли (два "ООО Ромашка") или лишние пробелы/кавычки. Если есть возможность, лучше искать контрагента по уникальному идентификатору — ИНН.
КонтрагентСсылка = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ИскомыйИНН);
Подведем итог: всегда следите за типами данных, которые вы передаете в параметры запроса 1С. Использование ТипЗнч() — лучший способ быстрой отладки, а поиск ссылки перед выполнением запроса — залог получения корректного результата.