Почему СКД "выкидывает" строки из результата запроса и как это исправить

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

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

Суть проблемы: исчезновение строк при изменении состава полей

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

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

Как работает оптимизатор запросов СКД

Система компоновки данных — это не статический текст запроса. Это динамический конструктор, который пересобирает SQL-запрос к базе данных «на лету» в зависимости от настроек пользователя. Основная цель этого механизма — оптимизация производительности.

Если в настройках отчета (в группировках, выбранных полях, отборах или условном оформлении) не используется какое-то поле, СКД считает его лишним. Чтобы не нагружать сервер базы данных передачей ненужной информации, оптимизатор полностью вырезает это поле из итогового текста запроса. Это касается не только финальной выборки, но и вложенных запросов, а также временных таблиц.

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


ВЫБРАТЬ
    ДАТАВРЕМЯ(1, 1, 1) КАК Период,
    ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка) КАК Сотрудник,
    ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка) КАК Организация
ПОМЕСТИТЬ Представления_ТаблицаРегистра_КадроваяИсторияСотрудников
ИЗ
    ВТОтборДляТаблицыРегистра КАК ОтборДляТаблицыРегистра

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

Решение 1: Использование роли поля "Обязательное"

Самый эффективный и быстрый способ запретить СКД выбрасывать поле из запроса — настроить его роль в наборе данных. Разберем по шагам, как это сделать:

  1. Откроем схему компоновки данных (отчет) в конфигураторе.
  2. Перейдем на закладку Наборы данных.
  3. Найдем в списке полей нужный нам объект (например, Организация).
  4. В колонке Роли нажмем на кнопку выбора (лупа или три точки).
  5. В открывшемся окне установим флаг Обязательное.

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

Решение 2: Отключение флага "Автозаполнение"

Если мы хотим полностью контролировать текст запроса и не доверяем автоматике СКД, мы можем отключить механизм Автозаполнение.

Проанализируем последствия этого действия: когда флаг Автозаполнение (на закладке "Наборы данных") снят, СКД перестает автоматически определять доступные поля и их роли. В этом случае нам придется вручную описать каждое поле в секции "Компоновка данных" конструктора запроса. Поля, которые просто указаны в тексте запроса, но не вынесены в расширение компоновки, не будут модифицироваться оптимизатором динамически. Это более сложный путь, требующий аккуратности, но он дает 100% предсказуемый результат.

Как проанализировать итоговый запрос

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

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

2. Программный вывод в событии ПриКомпоновкеДанных. Мы можем перехватить процесс формирования отчета в модуле объекта и выгрузить макет компоновки. Рассмотрим фрагмент кода для отладки:


Процедура ПриКомпоновкеДанных(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Установим стандартную обработку в Ложь, чтобы управлять процессом
    СтандартнаяОбработка = Ложь;
    
    // Создаем компоновщик макета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    // Генерируем макет для исполнения
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
    
    // В переменной МакетКомпоновки в наборах данных теперь можно увидеть реальный текст запроса
    // Для этого удобно использовать отладчик или записать текст в файл
    Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
        Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросМакетКомпоновкиДанных") Тогда
            ТекстЗапросаДляАнализа = НаборДанных.Запрос;
        КонецЕсли;
    КонецЦикла;

    // Далее необходимо завершить процесс вывода отчета
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Сравнив текст запроса, когда поле Организация выбрано, и текст, когда оно отключено, мы увидим, что оптимизатор вырезает его из всех вложенных структур, что и меняет логику группировки данных в базе.

Особенности работы с механизмами представлений (ЗУП 3.1)

В типовых решениях, таких как «Зарплата и управление персоналом», часто используются временные таблицы с предопределенными именами (например, Представления_ТаблицаРегистра_КадроваяИсторияСотрудников). Эти таблицы обрабатываются специальными программными механизмами в общем модуле ЗарплатаКадрыОбщие.

Если СКД модифицирует запрос к такой таблице, удаляя поля-измерения, то функции формирования представлений могут вернуть некорректный срез данных. Выясним причину: механизм построения виртуальных таблиц кадровой истории опирается на состав полей, запрошенных в СКД. Если Организация не запрошена, система может построить срез последних данных только по Сотруднику, игнорируя его перемещения между филиалами. В этом случае установка роли Обязательное является единственным верным способом сохранить корректность кадрового учета в отчете.

Резюме

Подведем итоги. Если в СКД пропадают строки при изменении настроек:

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

← На главную