При разработке отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда запрос, прекрасно работающий в консоли запросов, выдает ошибку в самом отчете. Одна из самых коварных ошибок — «В выборке должно быть указано хотя бы одно измерение или ресурс». Особенно странно это выглядит, когда мы просто меняем состав выбранных полей в настройках отчета. Давайте подробно разберем, почему это происходит и как правильно настроить схему компоновки, чтобы отчет работал стабильно.
Рассмотрим пример запроса, который вызывает проблему. В нем используется временная таблица для получения базы распределения (например, общей суммы доходов), которая затем соединяется с основной таблицей оборотов для расчета долей или распределения сумм.
ВЫБРАТЬ
ДвиженияДенежныеСредстваКонтрагентОбороты.СуммаОплатыОборот КАК Сумма
ПОМЕСТИТЬ БазаРаспределения1
ИЗ
РегистрНакопления.ДвиженияДенежныеСредстваКонтрагент.Обороты(&НачПериода, &КонПериода, Авто, ...) КАК ДвиженияДенежныеСредстваКонтрагентОбороты;
///////////////////////////////////////////////////////////
ВЫБРАТЬ
ДвиженияДенежныеСредстваКонтрагентОбороты.СтатьяДвиженияДенежныхСредств КАК СтатьяДДС,
ДвиженияДенежныеСредстваКонтрагентОбороты.Подразделение КАК Подразделение,
СУММА(ДвиженияДенежныеСредстваКонтрагентОбороты.СуммаОплатыОборот) КАК СуммаВсего,
СУММА(БазаРаспределения1.Сумма) КАК Сумма
ИЗ
РегистрНакопления.ДвиженияДенежныеСредстваКонтрагент.Обороты(...) КАК ДвиженияДенежныеСредстваКонтрагентОбороты
ЛЕВОЕ СОЕДИНЕНИЕ БазаРаспределения1 КАК БазаРаспределения1
ПО (ИСТИНА)
СГРУППИРОВАТЬ ПО
ДвиженияДенежныеСредстваКонтрагентОбороты.СтатьяДвиженияДенежныхСредств,
ДвиженияДенежныеСредстваКонтрагентОбороты.Подразделение
Проблема проявляется так: когда в пользовательских настройках на закладке «Выбранные поля» включено поле Сумма, отчет формируется. Как только мы его убираем — получаем ошибку. Проанализируем причину такого поведения.
Система компоновки данных не отправляет ваш запрос в СУБД «как есть». Она выполняет трансформацию текста запроса, исходя из текущих настроек отчета (группировок, отборов, выбранных полей). Этот процесс называется интеллектуальной оптимизацией.
Разберем логику оптимизатора по шагам:
Сумма в настройках отчета.ВЫБРАТЬ итогового запроса.БазаРаспределения1 не выбрано ни одного поля, оптимизатор решает, что и соединение с этой таблицей (ЛЕВОЕ СОЕДИНЕНИЕ ... ПО ИСТИНА) выполнять не нужно..Обороты), если из них не выбирается ни одно измерение или ресурс, платформа генерирует исключение, так как SQL-запрос не может содержать пустой оператор SELECT.Это самый быстрый и эффективный способ решения проблемы, когда логика вашего отчета завязана на соединениях, которые нельзя разрывать. Нам нужно принудительно запретить оптимизатору удалять поле из запроса.
Рассмотрим алгоритм действий:
Сумма из временной таблицы).Что это дает? Установка этого флага сообщает СКД: «Это поле должно присутствовать в итоговом SQL-запросе всегда, даже если пользователь не вывел его в отчет». В результате соединение с временной таблицей сохранится, и структура запроса не нарушится.
Зачастую соединение ПО ИСТИНА (декартово произведение) используется для получения общего итога во всех строках отчета. Это ресурсоемкая операция. Проанализируем альтернативный подход с использованием возможностей самого процессора компоновки.
Вместо того чтобы тянуть общую сумму через соединение в запросе, мы можем рассчитать её на уровне ресурсов СКД. Для этого:
Сумма(ВычислитьВыражение("СуммаОплатыОборот", , "ОбщийИтог")).Этот метод работает быстрее, так как платформа вычисляет итог один раз и «раздает» его во все строки без выполнения тяжелых SQL-соединений.
Иногда оптимизатор СКД ошибочно сопоставляет поля с одинаковыми именами из разных таблиц. Посмотрим, как это исправить. Если в первой временной таблице поле называется Сумма, и в основном запросе есть поле Сумма, компоновщик может запутаться при исключении полей.
Попробуйте дать уникальные имена полям во временных таблицах, например:
ВЫБРАТЬ
СуммаОплатыОборот КАК СуммаДляРаспределения
ПОМЕСТИТЬ БазаРаспределения1
...
Хотя этот способ помогает не всегда, он является хорошим тоном при написании сложных запросов в СКД, так как снижает вероятность неоднозначной трактовки полей оптимизатором.
Проанализируем риски, которые несет в себе конструкция ЛЕВОЕ СОЕДИНЕНИЕ ... ПО (ИСТИНА) в СКД:
БазаРаспределения1 окажется больше одной строки, все данные основного запроса «размножатся». Это приведет к катастрофически неверным итогам. Всегда следите, чтобы в такой таблице была строго одна строка (используйте СГРУППИРОВАТЬ ПО без полей или ВЫБРАТЬ ПЕРВЫЕ 1).ЛЕВОГО СОЕДИНЕНИЯ, если база распределения не рассчиталась (таблица пустая), во всех строках будет NULL. В выражениях ресурсов обязательно используйте функцию ЕСТЬNULL(Поле, 0).Мы выяснили, что ошибка «В выборке должно быть указано хотя бы одно измерение или ресурс» — это результат чрезмерной «заботы» оптимизатора СКД о производительности. Чтобы победить её, мы рассмотрели три способа:
ВычислитьВыражение в ресурсах (лучший способ с точки зрения производительности).Рекомендуем всегда проверять отчет с различными вариантами выбранных полей на этапе тестирования, чтобы исключить подобные сюрпризы у пользователей.