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