Как отфильтровать документы одного вида: ССЫЛКА, ТИПЗНАЧЕНИЯ, вид операции и СКД
Содержание
Чтобы сделать отбор по типу документа в запросе 1С, используйте оператор ССЫЛКА: условие ГДЕ Т.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг оставит только строки, созданные реализациями. Во встроенном языке то же самое делает сравнение ТипЗнч(Значение) = Тип("ДокументСсылка.РеализацияТоваровУслуг"). Если нужен не тип, а разновидность внутри одного документа, фильтруйте по реквизиту ВидОперации через ЗНАЧЕНИЕ(Перечисление...).
Приёмы общие для платформы 8.3 и не зависят от конфигурации. Примеры ниже написаны на объектах Бухгалтерии 3.0, но в УТ 11 или ЗУП 3.1 меняются только имена документов и регистров.
Отбор документов по типу в языке запросов
Задача обычно возникает при работе с полями составного типа. Самое частое из них — Регистратор в регистрах: туда пишут движения десятки видов документов. Второе — журналы документов и реквизиты вида «Документ-основание».
Оператор ССЫЛКА
Самый читаемый способ. Он проверяет, ссылается ли значение на объект указанного вида:
ВЫБРАТЬ
Х.Регистратор КАК Документ,
Х.СчетДт,
Х.СчетКт,
Х.Сумма
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Х
ГДЕ
Х.Период МЕЖДУ &НачалоПериода И &КонецПериода
И Х.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
Несколько видов объединяйте через ИЛИ, исключение делайте через НЕ. Так можно, например, убрать из выборки ручные операции:
ГДЕ
(Х.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
ИЛИ Х.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг)
И НЕ Х.Регистратор ССЫЛКА Документ.ОперацияБух
Функция ТИПЗНАЧЕНИЯ
ТИПЗНАЧЕНИЯ() возвращает тип значения, и его сравнивают с ТИП():
ГДЕ
ТИПЗНАЧЕНИЯ(Х.Регистратор) = ТИП(Документ.РеализацияТоваровУслуг)
Главный плюс — тип можно передать параметром. Список видов документов тогда не зашит в текст запроса, а собирается кодом:
ГДЕ
ТИПЗНАЧЕНИЯ(Х.Регистратор) В (&ТипыДокументов)
ТипыДокументов = Новый Массив;
Для Каждого ИмяДокумента Из СтрРазделить("РеализацияТоваровУслуг,ПоступлениеТоваровУслуг", ",") Цикл
ТипыДокументов.Добавить(Тип("ДокументСсылка." + ИмяДокумента));
КонецЦикла;
Запрос.УстановитьПараметр("ТипыДокументов", ТипыДокументов);
Как получить реквизиты отобранного документа
После отбора часто нужен реквизит самого документа, например контрагент. Обращаться через точку к составному полю (Х.Регистратор.Контрагент) не стоит: платформа соединит регистр со всеми таблицами документов, которые могут быть регистраторами. Приведите тип явно:
ВЫБРАТЬ
ВЫРАЗИТЬ(Х.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент,
СУММА(Х.Сумма) КАК Сумма
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Х
ГДЕ
Х.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
СГРУППИРОВАТЬ ПО
ВЫРАЗИТЬ(Х.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент
Какие виды документов вообще пишут в регистр
Перед отбором полезно узнать, из каких документов состоит регистр за период. Это быстрый способ найти точное имя вида и заодно заметить «чужие» документы, о которых никто не помнил:
ВЫБРАТЬ
ТИПЗНАЧЕНИЯ(Х.Регистратор) КАК ТипДокумента,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Х.Регистратор) КАК Документов,
СУММА(Х.Сумма) КАК Сумма
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Х
ГДЕ
Х.Период МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
ТИПЗНАЧЕНИЯ(Х.Регистратор)
УПОРЯДОЧИТЬ ПО
Документов УБЫВ
В консоли запросов колонка ТипДокумента покажет виды документов, а рядом — сколько их провелось за период. Дальше берите нужный вид и ставьте по нему отбор ССЫЛКА.
Условие из примеров можно не писать руками. В конструкторе запроса Конфигуратора откройте вкладку «Условия», включите флаг «Произвольное» и вставьте строку с ССЫЛКА. Конструктор сохранит её как есть.
Как сделать отбор по виду операции внутри документа
Тип документа и вид операции — разные вещи. «Списание с расчётного счёта» одним типом покрывает оплату поставщику, перечисление налога, выдачу подотчётному лицу. Различает их реквизит ВидОперации, и обычно он имеет тип перечисления.
Сравнение с элементом перечисления в запросе
Значение перечисления в тексте запроса задают функцией ЗНАЧЕНИЕ(). Строки и синонимы не подходят:
ВЫБРАТЬ
Спис.Ссылка,
Спис.Дата,
Спис.СуммаДокумента
ИЗ
Документ.СписаниеСРасчетногоСчета КАК Спис
ГДЕ
Спис.Дата МЕЖДУ &НачалоПериода И &КонецПериода
И Спис.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийСписаниеДенежныхСредств.ОплатаПоставщику)
И НЕ Спис.ПометкаУдаления
Для нескольких видов операций удобнее параметр-массив: Спис.ВидОперации В (&ВидыОпераций).
Как узнать точное имя перечисления
Имена перечислений различаются между конфигурациями и иногда между редакциями. Проверьте их сами, это занимает минуту:
- Откройте Конфигуратор и дерево метаданных (
Конфигурация → Открыть конфигурацию). - Разверните ветку
Документы, найдите нужный документ и его реквизитВидОперации. - В свойствах реквизита посмотрите поле «Тип» — там будет
ПеречислениеСсылка.<Имя>. - Откройте это перечисление в ветке
Перечисленияи скопируйте имя значения, а не синоним.
Вид операции у регистратора
Комбинация двух отборов: сначала тип регистратора, потом вид операции через приведение типа.
ГДЕ
Х.Регистратор ССЫЛКА Документ.СписаниеСРасчетногоСчета
И ВЫРАЗИТЬ(Х.Регистратор КАК Документ.СписаниеСРасчетногоСчета).ВидОперации
= ЗНАЧЕНИЕ(Перечисление.ВидыОперацийСписаниеДенежныхСредств.ОплатаПоставщику)
Проверка типа документа во встроенном языке
В коде модуля тип проверяют функцией ТипЗнч(). Сравнивать нужно со ссылочным типом, а не с типом объекта:
Если ТипЗнч(Основание) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
// заполнение по реализации
ИначеЕсли ТипЗнч(Основание) = Тип("ДокументСсылка.ПоступлениеТоваровУслуг") Тогда
// заполнение по поступлению
КонецЕсли;
Внутри модуля объекта (ОбработкаПроведения, ПередЗаписью) переменная ЭтотОбъект имеет тип ДокументОбъект.<Имя>. Ссылка на него — ЭтотОбъект.Ссылка.
Проверка «это вообще документ?»
Когда неважно, какой именно вид, а важно отличить документ от справочника или числа:
Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Значение)) Тогда
ИмяВида = Значение.Метаданные().Имя; // РеализацияТоваровУслуг
Синоним = Значение.Метаданные().Синоним; // название для пользователя
КонецЕсли;
Метаданные() у ссылки дают объект описания документа. Имя пригодится для логики, синоним — для сообщений пользователю.
Отбор строк коллекции по типу
Если данные уже в таблице значений, а переписать запрос нельзя, удаляйте строки обратным циклом. Прямой цикл с удалением пропускает строки, потому что индексы сдвигаются:
ТипОтбора = Тип("ДокументСсылка.РеализацияТоваровУслуг");
Для Сч = 1 По Таблица.Количество() Цикл
Строка = Таблица[Таблица.Количество() - Сч];
Если ТипЗнч(Строка.Регистратор) <> ТипОтбора Тогда
Таблица.Удалить(Строка);
КонецЕсли;
КонецЦикла;
Отбор по типу в коде после выборки — запасной вариант. На тысячах строк он медленнее, чем то же условие в тексте запроса.
Настройка отбора по типу документа в СКД
В системе компоновки данных пользователь может поставить отбор по полю Регистратор. Но вид сравнения «В списке» просит выбрать конкретные документы, а не их тип. Поэтому отбор по виду документа в отчёте на СКД готовят на уровне схемы.
Способ 1. Поле с названием вида
Добавьте в запрос набора данных вычисляемую колонку:
ВЫБОР
КОГДА Х.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
ТОГДА "Реализация"
КОГДА Х.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
ТОГДА "Поступление"
ИНАЧЕ "Прочие"
КОНЕЦ КАК ВидДокумента
Поле ВидДокумента появится в настройках отчёта. Пользователь ставит по нему отбор, группировку или выводит колонкой. Минус один: новые виды документов нужно дописывать в ВЫБОР руками.
Способ 2. Параметр со списком типов
В запрос набора данных добавьте условие ТИПЗНАЧЕНИЯ(Х.Регистратор) В (&ТипыДокументов). Значение параметра задайте из кода формы или модуля отчёта:
Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(
"ТипыДокументов", ТипыДокументов);
Массив ТипыДокументов собирается так же, как в разделе про запросы. Этот вариант лучше, когда виды документов выбирает программа, а не пользователь.
Способ 3. Условие прямо в схеме
Если отчёт всегда строится по одному виду документа, впишите ССЫЛКА в ГДЕ запроса набора данных. В настройках пользователя этот отбор не виден и случайно не снимается.
| Способ | Когда выбирать | Ограничение |
|---|---|---|
Поле ВидДокумента через ВЫБОР | Пользователь сам выбирает виды в отчёте | Новые виды дописывают вручную |
Параметр &ТипыДокументов | Список видов задаёт код | Нужен модуль отчёта или формы |
ССЫЛКА в тексте схемы | Отчёт только по одному виду | Отбор нельзя изменить без правки схемы |
Отбор в формах списков, журналах и динамических списках
Без программирования
В режиме «Предприятие» отбор по типу доступен там, где в одном списке собраны разные документы, то есть в журналах. У журнала документов есть стандартное поле Тип. Откройте меню «Ещё» над списком, перейдите к настройке списка и на закладке «Отбор» добавьте условие по полю типа документа.
Если журнала в интерфейсе нет, его можно открыть через Все функции → Журналы документов. Пункт «Все функции» включается в параметрах программы (Главное меню → Сервис → Параметры, флаг «Отображать команду “Все функции”»).
В списке документов одного вида отбор ставят по реквизиту «Вид операции». Он доступен в той же настройке списка, если реквизит есть у документа.
В запросе к журналу
Стандартное поле Тип у журнала работает и в запросе:
ВЫБРАТЬ
Ж.Ссылка,
Ж.Дата,
Ж.Номер
ИЗ
ЖурналДокументов.<ИмяЖурнала> КАК Ж
ГДЕ
Ж.Тип = ТИП(Документ.РеализацияТоваровУслуг)
Программно в динамическом списке
Отбор на форме списка ставят через свойство Отбор динамического списка:
&НаСервере
Процедура УстановитьОтборПоВидуОперации()
Список.Отбор.Элементы.Очистить();
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ВидОперации");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Перечисления.ВидыОперацийСписаниеДенежныхСредств.ОплатаПоставщику;
ЭлементОтбора.Использование = Истина;
КонецПроцедуры
Очистить() убирает прежние условия, иначе при повторном вызове они копятся. В конфигурациях на БСП то же делает одна строка: ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(Список, "ВидОперации", Значение). Она находит существующий элемент и меняет его, а не добавляет новый.
Если у динамического списка свой запрос (флаг «Произвольный запрос» в свойствах реквизита формы), отбор по типу проще вписать в текст: ГДЕ Т.Документ ССЫЛКА Документ.<Имя>.
Ошибки при отборе по типу и скорость запроса
Что ломается чаще всего
| Симптом | Причина | Что сделать |
|---|---|---|
Тип не определен (ДокументСсылка.Реализация товаров) | В Тип() указан синоним, а не имя объекта | Возьмите имя из дерева метаданных, без пробелов |
Условие с ТипЗнч никогда не срабатывает | Сравнение с ДокументОбъект.<Имя> вместо ДокументСсылка.<Имя> | В значении лежит ссылка, сравнивайте со ссылочным типом |
| Запрос не выбирает ни одной строки по виду операции | Вид операции сравнивается со строкой | Используйте ЗНАЧЕНИЕ(Перечисление.<Имя>.<Значение>) |
В колонке ВидОперации много NULL | Поле берётся через точку от составного Регистратор без отбора по типу | Добавьте ССЫЛКА и ВЫРАЗИТЬ к нужному виду |
| Отчёт стал медленным после добавления реквизита документа | Разыменование составного поля соединило все таблицы регистраторов | Замените Регистратор.Реквизит на ВЫРАЗИТЬ(...) |
| В выборку попадают удалённые документы | Отбор по типу не учитывает пометку удаления | Добавьте НЕ Т.ПометкаУдаления или условие Проведен |
Как не потерять в скорости
- 🔹 Проверка
ССЫЛКАиТИПЗНАЧЕНИЯу составного поля сводится к сравнению кода типа. Сама по себе она дешёвая. - 🔹 Сначала сужайте выборку по периоду (
Период МЕЖДУилиДата МЕЖДУ), потом по типу. На регистре за несколько лет разница заметна. - 🔹 Реквизит
ВидОперациив типовых документах обычно не индексирован. Без условия на дату запрос просматривает всю таблицу документа. - 🔹 Не тяните реквизиты через точку от
Регистратор: каждое такое обращение безВЫРАЗИТЬдобавляет соединения по всем видам регистраторов. - 🔹 Если отчёт тормозит, включите в Конфигураторе замер производительности при отладке. Он покажет, сколько времени уходит на строку
Запрос.Выполнить(), и станет ясно, виноват ли запрос.
Для запросов с отбором через ВЫРАЗИТЬ по большому регистру удобно проверять результат в консоли запросов на копии базы. Так видно и количество строк, и время выполнения.
Частые вопросы
Как получить список всех видов документов конфигурации?
Метаданные.Документы циклом Для Каждого. У каждого элемента есть Имя и Синоним, а тип ссылки получается так: Тип("ДокументСсылка." + МД.Имя).Чем ССЫЛКА отличается от ТИПЗНАЧЕНИЯ?
ССЫЛКА короче и читается проще, а ТИПЗНАЧЕНИЯ позволяет передать тип или массив типов параметром.Работает ли оператор ССЫЛКА для справочников?
Т.Субконто1 ССЫЛКА Справочник.Контрагенты отбирает строки, где в субконто стоит контрагент. Так же проверяются планы видов характеристик и другие ссылочные объекты.Можно ли отобрать документы по типу без Конфигуратора?
ССЫЛКА пишется в текст запроса так же, как в коде, править конфигурацию не нужно.Почему пустая ссылка проходит отбор по типу?
Т.Поле <> ЗНАЧЕНИЕ(Документ.<Имя>.ПустаяСсылка).