При построении так называемых «черных» запросов в платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с ситуацией, когда запрос, обрабатывающий несколько различных видов документов (например, ПриходнаяНакладная и Списание), возвращает пустой результат при добавлении нескольких секций Условие.
Рассмотрим подробно причины возникновения этой проблемы и разберем способы ее правильного решения.
Проанализируем исходный пример кода запроса, в котором возникла ошибка:
ТекстЗапроса = "
|Период с ВыбНачПериода по ВыбКонПериода;
|Товар = Документ.ПриходнаяНакладная.Товар, Документ.Списание.Товар;
|КоличествоПрихода = Документ.ПриходнаяНакладная.Количество;
|КоличествоСписания = Документ.Списание.Количество;
|ВидПрихода = Документ.ПриходнаяНакладная.ВидПоступления;
|ВидСписания = Документ.Списание.Причина;
|Функция КолПрихода = Сумма(КоличествоПрихода);
|Функция КолСписания = Сумма(КоличествоСписания);
|Группировка Товар;
|Группировка Документ;
|Условие(ВидПрихода = Перечисление.ВидыПоступления.ДоВыяснения);
|Условие(ВидСписания = Перечисление.ОснованиеСписания.ОшибочныйПриход);
|Условие(Товар в спТоваров);";
Выясним причину, почему такой запрос оказывается пустым:
Условие логически связывается с предыдущими оператором И (AND).ПриходнаяНакладная, переменная ВидСписания имеет неопределенное (пустое) значение, так как реквизит Причина принадлежит документу Списание. Соответственно, условие по ВидСписания возвращает Ложь. При обработке документа Списание аналогично пустой оказывается переменная ВидПрихода.В результате комбинация двух условий Условие(...) AND Условие(...) дает Ложь абсолютно для каждой строки выборки, и результат запроса остается пустым.
Для исправления ситуации необходимо объединить проверки реквизитов разных документов в одну секцию Условие с использованием явного оператора ИЛИ и скобок.
Посмотрим на исправленный вариант запроса:
ТекстЗапроса = "
|Период с ВыбНачПериода по ВыбКонПериода;
|Товар = Документ.ПриходнаяНакладная.Товар, Документ.Списание.Товар;
|КоличествоПрихода = Документ.ПриходнаяНакладная.Количество;
|КоличествоСписания = Документ.Списание.Количество;
|ВидПрихода = Документ.ПриходнаяНакладная.ВидПоступления;
|ВидСписания = Документ.Списание.Причина;
|Функция КолПрихода = Сумма(КоличествоПрихода);
|Функция КолСписания = Сумма(КоличествоСписания);
|Группировка Товар;
|Группировка Документ;
|Условие((ВидПрихода = Перечисление.ВидыПоступления.ДоВыяснения) ИЛИ (ВидСписания = Перечисление.ОснованиеСписания.ОшибочныйПриход));
|Условие(Товар в спТоваров);";
Теперь для каждого документа проверяется, подходит ли он под критерии прихода ИЛИ списания, а фильтр по списку товаров (Товар в спТоваров) применяется параллельно через отдельное условие.
Альтернативный и очень удобный способ в 1С 7.7 — перенести условия фильтрации непосредственно в описание функций с помощью ключевого слова Когда. Это позволяет избежать отсечения строк документов на общем уровне условий.
Разберем пример кода с использованием конструкций Когда:
ТекстЗапроса = "
|Период с ВыбНачПериода по ВыбКонПериода;
|Товар = Документ.ПриходнаяНакладная.Товар, Документ.Списание.Товар;
|КоличествоПрихода = Документ.ПриходнаяНакладная.Количество;
|КоличествоСписания = Документ.Списание.Количество;
|ВидПрихода = Документ.ПриходнаяНакладная.ВидПоступления;
|ВидСписания = Документ.Списание.Причина;
|Функция КолПрихода = Сумма(КоличествоПрихода) Когда (ВидПрихода = Перечисление.ВидыПоступления.ДоВыяснения);
|Функция КолСписания = Сумма(КоличествоСписания) Когда (ВидСписания = Перечисление.ОснованиеСписания.ОшибочныйПриход);
|Группировка Товар;
|Группировка Документ;
|Условие(Товар в спТоваров);";
При таком подходе функция Сумма будет рассчитываться только тогда, когда выполняется условие Когда(...) для конкретной строки документа.
Если логика выборки документов усложняется, можно использовать обход документов выборкой через встроенный язык платформы:
СоздатьОбъект("Документ.ПриходнаяНакладная") и СоздатьОбъект("Документ.Списание").ВыбратьДокументы(ВыбНачПериода, ВыбКонПериода).Пока Док.ПолучитьДокумент() = 1 Цикл выполняем проверку реквизитов средствами встроенного языка (Если...Тогда) и заносим результаты в объект ТаблицаЗначений.Этот способ работает максимально прозрачно и исключает специфическое поведение парсера запросов 1С 7.7.