Как получить полные данные из табличной части документа Табель с учетом пустых значений

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

В процессе разработки отчетов или обработок в системе 1С часто возникает задача получения данных из табличных частей документов. Одной из самых сложных структур обладает документ ТабельУчетаРабочегоВремени (в конфигурациях ЗУП 3.1 и ERP). Проблема заключается в том, что если по сотруднику за определенный период или по конкретному виду времени (например, «Ночные») нет записей в документе, то обычный запрос просто «пропустит» этого сотрудника или этот вид времени. В данной статье мы разберем, как построить запрос таким образом, чтобы получить полную картину, включая пустые строки.

Анализ проблемы: почему данные «исчезают»

Рассмотрим стандартный подход, который часто используют начинающие разработчики. Если мы обратимся напрямую к табличной части ДанныеОВремени, мы получим только те строки, которые физически записаны в базу данных. Проанализируем пример запроса:


ВЫБРАТЬ
    Табель.Сотрудник КАК Сотрудник,
    Табель.ВидВремени1 КАК ВидВремени,
    Табель.Часов1 КАК Часов
ИЗ
    Документ.ТабельУчетаРабочегоВремени.ДанныеОВремени КАК Табель
ГДЕ
    Табель.Ссылка = &Основной

В этом случае, если в документе для сотрудника заполнена только «Явка», но не заполнены «Ночные», в результате запроса будет всего одна строка. Если же нам требуется вывести «сетку» по всем возможным видам времени для каждого сотрудника (даже если часов там нет), такой прямой запрос не подходит. Система не может выдать данные, которых не существует в таблице. Выясним причину: нам не хватает опорной оси.

Решение: построение «опорной оси» для запроса

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

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


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Табель.Сотрудник КАК Сотрудник
ПОМЕСТИТЬ ВТ_Сотрудники
ИЗ
    Документ.ТабельУчетаРабочегоВремени.ДанныеОВремени КАК Табель
ГДЕ
    Табель.Ссылка = &СсылкаДокумента
;

Шаг 2. Формирование списка видов времени. Нам нужно определить, какие именно виды времени мы хотим видеть в отчете. Мы можем выбрать их из справочника ВидыИспользованияРабочегоВремени или задать фиксированным списком. Проанализируем ситуацию: чаще всего нужны «Явка», «Ночные» и «Сверхурочные».


ВЫБРАТЬ
    ВидыВремени.Ссылка КАК ВидВремени
ПОМЕСТИТЬ ВТ_ВидыВремени
ИЗ
    Справочник.ВидыИспользованияРабочегоВремени КАК ВидыВремени
ГДЕ
    ВидыВремени.Ссылка В (&МассивНужныхВидов)
;

Шаг 3. Создание «сетки» (Декартово произведение). Теперь мы соединяем таблицу сотрудников с таблицей видов времени без всякого условия связи. Это даст нам все возможные пары сотрудников и их видов времени.


ВЫБРАТЬ
    ВТ_Сотрудники.Сотрудник КАК Сотрудник,
    ВТ_ВидыВремени.ВидВремени КАК ВидВремени
ПОМЕСТИТЬ ВТ_ОпорнаяОсь
ИЗ
    ВТ_Сотрудники КАК ВТ_Сотрудники
        СОЕДИНЕНИЕ ВТ_ВидыВремени КАК ВТ_ВидыВремени
        ПО (ИСТИНА)
;

Объединение опорной оси с данными документа

Теперь, когда у нас есть полная сетка ВТ_ОпорнаяОсь, мы можем выполнить ЛЕВОЕ СОЕДИНЕНИЕ с реальной табличной частью документа. Посмотрим на пример реализации, учитывая особенности хранения данных в табеле (где виды времени распределены по колонкам ВидВремени1, ВидВремени2 и т.д.):


ВЫБРАТЬ
    Ось.Сотрудник КАК Сотрудник,
    Ось.ВидВремени КАК ВидВремени,
    ЕСТЬNULL(ДанныеДокумента.Часов, 0) КАК Часов
ИЗ
    ВТ_ОпорнаяОсь КАК Ось
ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ
        ТЧ.Сотрудник КАК Сотрудник,
        ТЧ.ВидВремени1 КАК ВидВремени,
        ТЧ.Часов1 КАК Часов
    ИЗ
        Документ.ТабельУчетаРабочегоВремени.ДанныеОВремени КАК ТЧ
    ГДЕ
        ТЧ.Ссылка = &СсылкаДокумента
    // Здесь может потребоваться ОБЪЕДИНЕНИЕ ВСЕ для всех 6 слоев ВидВремени в Табеле
) КАК ДанныеДокумента
ПО Ось.Сотрудник = ДанныеДокумента.Сотрудник
    И Ось.ВидВремени = ДанныеДокумента.ВидВремени

Важный момент: Обратите внимание на функцию ЕСТЬNULL. Именно она позволяет заменить отсутствие данных в документе на 0 или пустую строку, что и требовалось автору задачи. Если данных в документе нет, левое соединение вернет NULL, а функция преобразует его в читаемый вид.

Особенности архитектуры документа «Табель»

Проанализируем структуру табличной части ДанныеОВремени. Она является «горизонтальной» — в одной строке хранятся данные за весь месяц в колонках Часов1, Часов2 ... Часов31. Кроме того, для каждого дня может быть до 6 различных видов времени (слоев). Поэтому при написании запроса к ТЧ нужно помнить о следующем:

  1. Трансформация данных: Чтобы получить данные в вертикальном разрезе (одна дата — одна строка), часто требуется соединение с вспомогательной таблицей чисел (от 1 до 31).
  2. Производительность: Прямые запросы к табличным частям документов считаются «тяжелыми». Если документ содержит тысячи строк, запрос может работать медленно, так как ТЧ документов не индексируются в СУБД так же эффективно, как таблицы регистров.
  3. Регистры накопления: В типовых решениях (ЗУП, ERP) после проведения Табеля данные попадают в регистр Данные оперативного учета рабочего времени. Рассмотрим вариант использования регистра: данные там уже хранятся в «вертикальном» и удобном для запросов виде. Программистам рекомендуется обращаться именно к регистрам, если документ уже проведен.

Рекомендации по разработке

Подведем итог. Для качественного решения задачи получения «пустых» строк следуйте этим правилам:

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

← На главную