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