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