Разработка и Конфигурация · 10 мин
Как задать вид документа в запросе 1С
Как указать вид документа в запросе 1С: фильтр по ссылке, ССЫЛКА, параметры, работа с журналами в 7.7 и 8.x. Примеры кода и разбор ошибок.
Фраза «задать вид документа в запросе» встречается в двух разных контекстах платформы 1С. В версии 7.7 запросы строятся на встроенном языке с конструкцией «Запрос = СоздатьОбъект("Запрос")», и вид документа там задается через предопределенную переменную «ВидДокумента» или функцию «Документ.ВидДокумента()». В версиях 8.x запросы пишутся на языке запросов, и отбор по виду документа выполняется через тип ссылки — оператор «ССЫЛКА» или выбор конкретной таблицы документа.
Путаница возникает еще и потому, что в 7.7 существует понятие «журнал документов», объединяющий несколько видов, и запрос по журналу требует явно указать, какие виды документов обрабатывать. В 8.x аналогичная задача решается объединением выборок из разных таблиц или отбором по типу ссылки из составного поля.
Ниже разобраны оба подхода с примерами кода, типичными ошибками и способами проверить, что отбор сработал именно так, как задумано.
Как задается вид документа в запросе 1С 8.x
В платформе 8.x каждый вид документа — это отдельная таблица в языке запросов. Самый простой и надежный способ «задать вид» — обратиться напрямую к нужной таблице: Документ.РеализацияТоваровУслуг, Документ.ПоступлениеТоваровУслуг и так далее. Никакого дополнительного отбора по виду при этом не требуется — сама таблица уже ограничивает выборку одним видом.
Пример простейшего запроса к одному виду документов:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка,
| РеализацияТоваровУслуг.Дата,
| РеализацияТоваровУслуг.Контрагент
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));
Результат = Запрос.Выполнить().Выгрузить();
Если источником служит составное поле (например, реквизит «ДокументОснование», который может ссылаться на несколько видов документов), вид задается условием на тип ссылки. Для этого в языке запросов есть оператор «ССЫЛКА»:
ВЫБРАТЬ
Оплата.ДокументОснование КАК Основание
ИЗ
Документ.ОплатаПлатежнойКартой КАК Оплата
ГДЕ
Оплата.ДокументОснование ССЫЛКА Документ.РеализацияТоваровУслуг
Отбор по виду через параметр запроса
Иногда вид документа должен определяться в момент выполнения, а не жестко прописываться в тексте запроса. Универсальный прием — передать в параметр пустую ссылку нужного вида и сравнивать тип поля с типом параметра через «ССЫЛКА» либо сравнивать само значение, если известен конкретный документ.
Когда вид выбирает пользователь, удобно передавать имя вида строкой и подставлять его в текст запроса программно. Это допустимо только для имени таблицы, полученного из метаданных, — подставлять произвольный пользовательский ввод в текст запроса нельзя, это риск ошибок и инъекций:
ИмяВида = "РеализацияТоваровУслуг"; // получено из метаданных
ТекстЗапроса = СтрШаблон(
"ВЫБРАТЬ Док.Ссылка, Док.Дата
|ИЗ Документ.%1 КАК Док
|ГДЕ Док.Проведен", ИмяВида);
Безопасный вариант — проверить имя через метаданные перед подстановкой: Если Метаданные.Документы.Найти(ИмяВида) = Неопределено Тогда Возврат; КонецЕсли;. Так вы гарантируете, что в запрос попадет только существующий вид документа.
Как задать вид документа в запросе 1С 7.7
В «семерке» запрос описывается текстом на встроенном языке, и вид документа фигурирует в двух местах: в объявлении переменной выборки и в условии обработки. Классический шаблон выглядит так:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с НачДата по КонДата;
|ОбрабатыватьДокументы Проведенные;
|Реал = Документ.Реализация.ТекущийДокумент;
|Контрагент = Документ.Реализация.Контрагент;
|Группировка Контрагент;
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Возврат;
КонецЕсли;
Здесь вид документа задан явно: Документ.Реализация. Если запрос строится по журналу, где хранятся документы разных видов, используется предопределенный атрибут «ВидДокумента» и функция фильтрации:
ТекстЗапроса =
"//{{ЗАПРОС(ПоЖурналу)
|Период с НачДата по КонДата;
|Док = Журнал.РасчетыСКлиентами.ТекущийДокумент;
|ВидДок = Журнал.РасчетыСКлиентами.ВидДокумента;
|Условие(ВидДок = ""Реализация"");
|"//}}ЗАПРОС
;
Условие сравнивает строковое представление вида документа с заданным именем. Имя должно совпадать с идентификатором вида в конфигураторе — с учетом регистра и без пробелов. Опечатка в имени не вызывает ошибку выполнения, а просто дает пустую выборку, что затрудняет диагностику.
Выборка документов нескольких видов
Когда нужно получить документы двух и более видов одним запросом, в 8.x применяют ОБЪЕДИНИТЬ ВСЕ. Каждая секция выбирает данные из своей таблицы, а набор колонок приводится к общему виду:
ВЫБРАТЬ
Реализация.Ссылка КАК Документ,
Реализация.Дата КАК Дата,
Реализация.СуммаДокумента КАК Сумма
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Возврат.Ссылка,
Возврат.Дата,
-Возврат.СуммаДокумента
ИЗ
Документ.ВозвратТоваровОтПокупателя КАК Возврат
ГДЕ
Возврат.Проведен
Альтернатива — виртуальные таблицы регистров. Если все нужные виды документов являются регистраторами одного регистра (например, регистра накопления «Продажи»), запрос к регистру с отбором по регистратору заданного типа часто работает быстрее, чем объединение таблиц документов, и сразу дает готовые итоги.
Сравнение подходов
Просто и быстро, но только один вид за раз; для нескольких видов нужно ОБЪЕДИНИТЬ ВСЕ.
Подходит, когда вид хранится в реквизите (основание, расчетный документ); не работает для самостоятельного списка документов.
Оптимален для отчетов по движениям; требует, чтобы документы были регистраторами одного регистра.
Проверка результата и производительность
После написания запроса проверьте его в консоли запросов: убедитесь, что в выборку попали документы только нужного вида, а количество строк соответствует списку в журнале за тот же период с теми же отборами. Расхождение чаще всего объясняется отсутствием условия по проведенности или неверными границами периода (время у даты окончания).
С точки зрения производительности условие «ССЫЛКА» по индексированному полю работает быстро, но отбор по неиндексированному составному реквизиту в большой таблице может привести к полному сканированию. Если такой отбор выполняется часто, рассмотрите добавление отдельного индексируемого реквизита или критерия отбора.
Как проверить результат
Все строки содержат документы только заданного вида
Попадают документы других видов или пустые ссылки
Совпадает с отфильтрованным журналом за тот же период
Меньше — проверьте условие по Проведен и границы дат
Запрос отрабатывает за секунды на рабочей базе
Многоминутное выполнение — проверьте индексы и соединения
Частые ограничения и нюансы
В запросе нельзя использовать конструкцию «ССЫЛКА» с перечислением нескольких видов через запятую — для нескольких типов применяют несколько условий через ИЛИ или соединение с таблицей значений, переданной как параметр. Также помните, что у документов разных видов разный состав реквизитов: в объединении обращаться можно только к полям, приведенным к общему набору.
В 7.7 своя специфика: запрос по журналу без условия по виду обработает все документы журнала, что на больших базах заметно медленнее. Кроме того, функция «ОбрабатыватьДокументы» с параметром «Все» включает в выборку и помеченные на удаление документы — для сводных отчетов обычно нужен режим «Проведенные».
Что важно запомнить
В 8.x вид документа задается таблицей запроса или оператором ССЫЛКА, в 7.7 — указанием вида в тексте запроса или условием по ВидДокумента. Всегда дополняйте отбор по виду условием по проведенности и проверяйте результат в консоли запросов.
Частые вопросы
Как в запросе 8.x проверить, что ссылка относится к конкретному виду документа?
Используйте оператор «ССЫЛКА»: условие «Поле ССЫЛКА Документ.РеализацияТоваровУслуг» вернет истину только для ссылок указанного вида. Это работает и для составных реквизитов, и для параметров запроса.
Можно ли передать вид документа в запрос параметром?
Напрямую имя таблицы параметром передать нельзя. Передайте в параметр пустую ссылку нужного вида и сравнивайте типы, либо сформируйте текст запроса программно, проверив имя вида через Метаданные.Документы.Найти().
Почему условие по виду в 7.7 дает пустую выборку?
Чаще всего имя вида в функции Условие не совпадает с идентификатором в конфигураторе. Сверьте написание посимвольно, включая регистр букв, и убедитесь, что в журнале за выбранный период вообще есть документы этого вида.
Как выбрать документы нескольких видов одним запросом?
В 8.x используйте ОБЪЕДИНИТЬ ВСЕ с одинаковым набором колонок в каждой секции. Если все виды — регистраторы одного регистра, эффективнее построить запрос к виртуальной таблице регистра с отбором по типу регистратора.
Чем отличается отбор по виду от отбора по конкретному документу?
Отбор по виду ограничивает тип ссылки (все документы этого вида), а отбор по документу сравнивает ссылку с конкретным значением, переданным параметром: «Ссылка = &Документ». Второй вариант быстрее, так как использует уникальный индекс ссылки.
Нужно ли добавлять условие по проведенности вместе с отбором по виду?
Да, если отчет должен отражать учетные данные. Отбор по виду сам по себе включает непроведенные и помеченные на удаление документы. Добавьте условие «Проведен» (или «Проведен = ИСТИНА»), чтобы исключить их из выборки.