При разработке отчетов в Системе компоновки данных (СКД) программисты часто сталкиваются с необходимостью отфильтровать данные регистра накопления по конкретному типу документа-источника (регистратора). Например, в регистре накопления ПартииТоваровНаСкладах могут делать записи десятки различных документов: РеализацияТоваровУслуг, ПоступлениеТоваровУслуг, ОприходованиеТоваров, СписаниеТоваров, ПеремещениеТоваров и другие. Что делать, если в отчете нужно вывести данные только по двум типам документов (например, оприходованию и списанию) и при этом дать пользователю удобную возможность управлять этим отбором?
В этой статье мы подробно разберем несколько практических способов реализации такого отбора — от простых условий в запросе до продвинутых и максимально оптимизированных методов с использованием встроенных механизмов СКД.
Рассмотрим ситуацию, когда требования к отчету однозначно определяют: данные должны выбираться только для конкретных видов документов, и пользователю не нужно давать возможность этот список расширять. В этом случае проще всего наложить ограничение непосредственно в тексте запроса с помощью оператора ССЫЛКА.
Давайте проанализируем исходный запрос, который выбирает данные из регистра накопления:
ВЫБРАТЬ
ПартииТоваровНаСкладах.Период,
ПартииТоваровНаСкладах.Регистратор,
ПартииТоваровНаСкладах.Номенклатура,
ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
ПартииТоваровНаСкладах.Количество,
ПартииТоваровНаСкладах.Стоимость,
ПартииТоваровНаСкладах.Регистратор.Подразделение КАК Подразделение,
ПартииТоваровНаСкладах.Основание
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах КАК ПартииТоваровНаСкладах
Чтобы ограничить выборку документов только типами ОприходованиеТоваров и СписаниеТоваров, мы добавим в секцию ГДЕ проверку типа ссылки регистратора:
ВЫБРАТЬ
ПартииТоваровНаСкладах.Период,
ПартииТоваровНаСкладах.Регистратор,
ПартииТоваровНаСкладах.Номенклатура,
ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
ПартииТоваровНаСкладах.Количество,
ПартииТоваровНаСкладах.Стоимость,
ПартииТоваровНаСкладах.Регистратор.Подразделение КАК Подразделение,
ПартииТоваровНаСкладах.Основание
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах КАК ПартииТоваровНаСкладах
ГДЕ
(ПартииТоваровНаСкладах.Регистратор ССЫЛКА Документ.ОприходованиеТоваров
ИЛИ ПартииТоваровНаСкладах.Регистратор ССЫЛКА Документ.СписаниеТоваров)
Преимущества метода:
Недостатки метода:
ПеремещениеТоваров, программисту придется переписывать отчет.Если мы хотим дать пользователю возможность самостоятельно выбирать типы документов в настройках отчета, то одним из очевидных решений является вычисление типа регистратора прямо в запросе. Для этого используется встроенная функция ТИПЗНАЧЕНИЯ.
Модифицируем наш запрос следующим образом:
ВЫБРАТЬ
ПартииТоваровНаСкладах.Период,
ПартииТоваровНаСкладах.Регистратор,
ПартииТоваровНаСкладах.Номенклатура,
ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
ПартииТоваровНаСкладах.Количество,
ПартииТоваровНаСкладах.Стоимость,
ПартииТоваровНаСкладах.Регистратор.Подразделение КАК Подразделение,
ПартииТоваровНаСкладах.Основание,
ТИПЗНАЧЕНИЯ(ПартииТоваровНаСкладах.Регистратор) КАК ТипДокумента
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах КАК ПартииТоваровНаСкладах
После добавления поля ТипДокумента выполним следующие шаги в конструкторе СКД:
ТипДокумента в список отборов.Равно или В списке, и выведем этот отбор на форму (сделаем его быстрым доступом для пользователя).Важное предупреждение о производительности! Этот метод таит в себе серьезную опасность для больших баз данных. Дело в том, что поле Регистратор имеет составной тип данных, который может состоять из десятков различных документов. При выполнении функции ТИПЗНАЧЕНИЯ(Регистратор) на уровне СУБД (например, MS SQL Server или PostgreSQL) генерируется огромная конструкция CASE WHEN ... THEN ... для сопоставления внутренних табличных идентификаторов типов. Если в регистре накопления содержатся миллионы записей, СУБД будет вынуждена произвести полное сканирование таблицы (Table Scan), что приведет к колоссальной нагрузке на процессор сервера и долгому формированию отчета.
Платформа 1С:Предприятие обладает мощными встроенными механизмами оптимизации, о которых начинающие разработчики часто не знают. СКД умеет самостоятельно накладывать эффективные SQL-фильтры по типам составных полей. Мы можем организовать отбор без искусственного добавления поля ТИПЗНАЧЕНИЯ в запрос.
Давайте разберем по шагам, как это настроить:
ТипДокумента).Регистратор.Тип — если пользователю нужно выбрать строго один вид документа (например, только ДокументСсылка.СписаниеТоваров).В списке типов (или Тип в списке) — если нужно предоставить пользователю возможность выбрать несколько видов документов одновременно.Почему это оптимально: При использовании этого механизма платформа 1С на уровне генерации итогового SQL-запроса подставит точные условия проверки типов без тяжелых вычислений «на лету». СУБД отработает этот запрос максимально быстро, используя индексы таблицы регистрации.
Если нам необходимо совместить гибкость пользовательского интерфейса и жесткое ограничение разработчика, лучшим решением станет использование расширения языка запросов СКД — фигурных скобок {ГДЕ ...}.
Посмотрим, как выглядит такой запрос:
ВЫБРАТЬ
ПартииТоваровНаСкладах.Период,
ПартииТоваровНаСкладах.Регистратор,
ПартииТоваровНаСкладах.Номенклатура,
ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
ПартииТоваровНаСкладах.Количество,
ПартииТоваровНаСкладах.Стоимость,
ПартииТоваровНаСкладах.Регистратор.Подразделение КАК Подразделение,
ПартииТоваровНаСкладах.Основание
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах КАК ПартииТоваровНаСкладах
{ГДЕ
(ПартииТоваровНаСкладах.Регистратор ССЫЛКА Документ.ОприходованиеТоваров
ИЛИ ПартииТоваровНаСкладах.Регистратор ССЫЛКА Документ.СписаниеТоваров)}
Как это работает:
ССЫЛКА в результирующий SQL-запрос, обеспечивая высокое быстродействие системы.Бывают задачи, когда стандартное окно выбора типов в СКД кажется пользователю слишком сложным или перегруженным (ведь там отображается весь список документов конфигурации). Мы можем сузить этот список до конкретных значений программным путем.
Рассмотрим, как это реализовать:
ТипДокументаРегистратора.ОписаниеТипов. В ограничении типов выберем только те документы, которые разрешено выбирать пользователю (например, ДокументСсылка.ОприходованиеТоваров и ДокументСсылка.СписаниеТоваров).ПриКомпоновкеРезультата, который будет считывать значение этого параметра и динамически добавлять элемент отбора в компоновщик настроек:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Получаем текущие настройки отчета
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Находим наш параметр
ПараметрТип = Настройки.ПараметрыДанных.Элементы.Найти("ТипДокументаРегистратора");
Если ПараметрТип <> Неопределено И ПараметрТип.Использование И ЗначениеЗаполнено(ПараметрТип.Значение) Тогда
// Создаем новый элемент отбора по полю Регистратор
НовыйОтбор = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Регистратор");
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Тип;
НовыйОтбор.ПравоеЗначение = ПараметрТип.Значение;
НовыйОтбор.Использование = Истина;
КонецЕсли;
// Выполняем компоновку с новыми настройками
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Этот метод сочетает в себе максимальное удобство для конечного пользователя (которому не нужно блуждать по огромному списку метаданных) и высокую производительность запросов к базе данных.
Мы подробно разобрали пять различных подходов к решению задачи. Подведем итоги:
ССЫЛКА в запросе).Тип/В списке типов в настройках СКД) — это наиболее производительный стандартный способ.ТИПЗНАЧЕНИЯ в тяжелых запросах к регистрам накопления (Решение 2), чтобы не перегружать сервер СУБД излишними операциями сканирования таблиц.ОписаниеТипов (Решение 5).