Почему в отчете СКД при выборе периода выводятся все данные и как это исправить

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов в Системе компоновки данных (СКД) на платформе 1С:Предприятие разработчики часто сталкиваются с неприятной ситуацией: пользователь выбирает конкретный период в настройках отчета (например, текущий месяц), но в результат все равно выводятся абсолютно все данные, включая документы за прошлые периоды. Рассмотрим подробно, почему так происходит, разберем типичные ошибки и изучим несколько эффективных способов решения этой проблемы.

Выясняем причину: Физические таблицы против виртуальных

Главная причина, по которой отбор по периоду не срабатывает автоматически, кроется в структуре самого запроса. Проанализируем, к каким таблицам базы данных идет обращение в отчете.

В системе 1С существует два принципиально разных типа таблиц:

  1. Виртуальные таблицы регистров (например, РегистрНакопления.ЗаказыПокупателей.ОстаткиИОбороты). СКД «дружит» с ними нативно. Она автоматически распознает параметры начала и окончания периода, связывает их с пользовательскими настройками и сама передает их в параметры виртуальной таблицы при генерации отчета.
  2. Физические таблицы документов и справочников (например, Документ.РСУ_РасходныйОрдер, Документ.Маршрут). Для этих таблиц СКД не накладывает фильтрацию по умолчанию. Если мы просто выбираем данные из документов, платформа выберет абсолютно всю историю за все годы, проигнорировав установленный пользователем период в шапке отчета. Чтобы ограничить выборку, разработчик обязан явно указать условия фильтрации.

Рассмотрим по шагам все возможные варианты решения этой задачи — от простой доработки запроса к документам до правильного перехода на использование регистров накопления.

Решение №1: Явное наложение условий в секции ГДЕ

Если специфика вашей задачи требует получения данных именно из физических таблиц документов, нам необходимо вручную ограничить выборку в тексте запроса с помощью параметров. Добавим условие фильтрации по дате документа.

Для этого в конструкторе запроса на вкладке «Условия» или вручную в тексте запроса пропишем следующее условие:


ВЫБРАТЬ
    Маршрут.Дата КАК Дата,
    РСУ_РасходныйОрдер.Ссылка КАК РасходныйОрдер,
    РСУ_РасходныйОрдер.Автор КАК Автор
ИЗ
    Документ.РСУ_РасходныйОрдер КАК РСУ_РасходныйОрдер
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.Маршрут КАК Маршрут 
        ПО РСУ_РасходныйОрдер.ПС_ДокМаршрут = Маршрут.Ссылка
ГДЕ
    РСУ_РасходныйОрдер.Дата МЕЖДУ &НачалоПериода И &КонецПериода

Также в СКД крайне полезно использовать синтаксис фигурных скобок для построения необязательных (расширяемых) отборов. Это позволит отчету работать корректно, даже если пользователь решит вообще не заполнять период:


ГДЕ
    {РСУ_РасходныйОрдер.Дата МЕЖДУ &НачалоПериода И &КонецПериода}

Решение №2: Правильная настройка связи параметров со «Стандартным периодом»

После того как мы добавили параметры &НачалоПериода и &КонецПериода в запрос, пользователю будет неудобно заполнять их вручную по отдельности в двух разных полях календаря. Гораздо удобнее предоставить единое поле выбора СтандартныйПериод (где можно выбрать «Этот месяц», «Вчера», «Прошлый квартал» и т. д.).

Свяжем эти параметры в схеме компоновки данных. Выполним следующие настройки:

  1. Перейдем на вкладку «Параметры» в СКД.
  2. Добавим новый параметр, назовем его Период и установим для него тип данных СтандартныйПериод.
  3. Для параметров НачалоПериода и КонецПериода в колонке «Ограничение доступности» установим флажки (галочки). Это скроет их от пользователя, чтобы он не путался.
  4. В колонке «Выражение» для параметра НачалоПериода укажем: &Период.ДатаНачала.
  5. В колонке «Выражение» для параметра КонецПериода укажем: &Период.ДатаОкончания.
  6. Перейдем на вкладку «Настройки», выберем вкладку «Параметры» внизу и добавим наш параметр Период в состав пользовательских настроек (кнопка со свойствами элемента пользовательских настроек), установив режим отображения «Быстрый доступ».

Благодаря этой настройке пользователь будет выбирать один удобный интервал в шапке отчета, а СКД автоматически разложит его на две крайние даты и передаст их в запрос.

Решение №3: Переход на использование виртуальных таблиц регистров накопления

Обращение напрямую к таблицам документов в отчетах считается неоптимальной практикой в среде 1С. Физические таблицы документов не индексируются по произвольным реквизитам табличных частей, что приводит к сильному замедлению работы базы данных по мере роста объема информации. Кроме того, при прямом запросе к документам в отчет могут попасть непроведенные, помеченные на удаление или пустые документы.

Проанализируем архитектуру регистров. Гораздо правильнее получать стоимостные, количественные и номенклатурные показатели из виртуальных таблиц оборотов или остатков соответствующих регистров накопления (например, ЗаказыПокупателей.ОстаткиИОбороты). Виртуальные таблицы работают значительно быстрее, а платформа гарантирует, что в них содержатся только движения реально проведенных документов.

Решение №4: Исправление ошибок пакетного запроса при связи документов и регистров

Иногда требуется соединить данные из документов (например, автора или дополнительные реквизиты, которых нет в движениях) с данными из регистра накопления. Для этого часто используют временные таблицы.

Разберем типичную ошибку начинающих разработчиков при написании пакетных запросов. Посмотрим на некорректную структуру пакета:


// ОШИБКА: Первый запрос пытается выбрать данные, но временная таблица еще не создана!
ВЫБРАТЬ
    РСУ_РасходныйОрдер.Автор КАК Автор,
    ЗаказПокуп.Номенклатура КАК Номенклатура
ИЗ
    Документ.РСУ_РасходныйОрдер КАК РСУ_РасходныйОрдер;

////////////////////////////////////////////////////////////////////////////////
// Помещение во временную таблицу идет вторым шагом - это вызовет ошибку компиляции!
ВЫБРАТЬ
    ЗаказыПокупателейОстаткиИОбороты.Номенклатура
ПОМЕСТИТЬ ЗаказПокуп
ИЗ
    РегистрНакопления.ЗаказыПокупателей.ОстаткиИОбороты(&ДатаНач, &ДатаКон) КАК ЗаказыПокупателейОстаткиИОбороты;

Правило пакета запросов: любая временная таблица должна быть создана (помещена в память с помощью инструкции ПОМЕСТИТЬ) строго ДО того, как к ней обратятся в последующих запросах пакета. Кроме того, во временной таблице обязательно должно быть ключевое поле связи (например, ссылка на документ-регистратор или заказ), по которому мы выполним соединение.

Рассмотрим правильный вариант построения пакетного запроса для нашего отчета:


// ШАГ 1: Создаем ВТ и выбираем данные из регистра, обязательно включая поле связи (ЗаказПокупателя)
ВЫБРАТЬ
    ЗаказыПокупателейОстаткиИОбороты.ЗаказПокупателя КАК ЗаказПокупателя,
    ЗаказыПокупателейОстаткиИОбороты.Номенклатура КАК Номенклатура,
    ЗаказыПокупателейОстаткиИОбороты.Номенклатура.Вес КАК Вес,
    ЗаказыПокупателейОстаткиИОбороты.Номенклатура.Объем КАК Объем
ПОМЕСТИТЬ ВТ_Заказы
ИЗ
    РегистрНакопления.ЗаказыПокупателей.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ) КАК ЗаказыПокупателейОстаткиИОбороты;

////////////////////////////////////////////////////////////////////////////////
// ШАГ 2: Выполняем основной запрос к документам и соединяем его с нашей ВТ_Заказы
ВЫБРАТЬ
    РСУ_РасходныйОрдер.Автор КАК АвторРасходногоОрдера,
    ПеремещениеТМЦ.Автор КАК АвторПеремещения,
    РСУ_РасходныйОрдер.ПС_ДатаОтгрузки КАК Дата,
    ВТ_Заказы.Номенклатура КАК Номенклатура,
    ВТ_Заказы.Вес КАК Вес,
    ВТ_Заказы.Объем КАК Объем
ИЗ
    Документ.РСУ_РасходныйОрдер КАК РСУ_РасходныйОрдер
    
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.Маршрут КАК Маршрут 
        ПО РСУ_РасходныйОрдер.ПС_ДокМаршрут = Маршрут.Ссылка
        
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПеремещениеТМЦ КАК ПеремещениеТМЦ 
        ПО РСУ_РасходныйОрдер.ДокРасход = ПеремещениеТМЦ.Ссылка
        
    // Получаем Ссылку заказа из шапки или табличной части документа
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказПокупателя КАК ЗаказПокупателя 
        ПО Маршрут.ТЧ.ДокЗаказПокупателя = ЗаказПокупателя.Ссылка
        
    // Соединяем с временной таблицей по ключевому полю связи
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Заказы КАК ВТ_Заказы 
        ПО ВТ_Заказы.ЗаказПокупателя = ЗаказПокупателя.Ссылка

Решение №5: Использование механизма «Связи наборов данных» в СКД

Для того чтобы не перегружать один запрос сложными левыми соединениями и временными таблицами, мы можем воспользоваться мощным альтернативным инструментом самой платформы СКД — связями наборов данных.

Реализуем это по шагам:

  1. Создадим НаборДанных1 (Запрос). В нем напишем простой запрос только к физическим таблицам документов (получим информацию по расходным ордерам, авторам и заказам покупателей). Условия по периоду здесь можно не указывать, если мы хотим видеть структуру документов.
  2. Создадим НаборДанных2 (Запрос). В нем напишем запрос к виртуальной таблице регистра накопления с параметрами начала и окончания периода:
    
    ВЫБРАТЬ
        ЗаказыПокупателейОстаткиИОбороты.ЗаказПокупателя КАК ЗаказПокупателя,
        ЗаказыПокупателейОстаткиИОбороты.Номенклатура КАК Номенклатура,
        ЗаказыПокупателейОстаткиИОбороты.КоличествоОборот КАК Кол
    ИЗ
        РегистрНакопления.ЗаказыПокупателей.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ) КАК ЗаказыПокупателейОстаткиИОбороты
    
  3. Перейдем на вкладку «Связи наборов данных».
  4. Добавим новую строку связи:
    • Источник связи: НаборДанных1
    • Приемник связи: НаборДанных2
    • Условие связи: ЗаказПокупателя = ЗаказПокупателя
    • Параметры: При необходимости СКД сама передаст нужные параметры из источника связи в параметры приемника.

Платформа выполнит компоновку данных на уровне СУБД максимально эффективно. СКД самостоятельно выберет документы, а затем для каждой строки документов подтянет отфильтрованные по периоду показатели из регистра. Это исключит дублирование строк и избавит от необходимости писать громоздкие sql-пакеты.

← На главную