Как объединить таблицу норм выдачи и таблицу фактических остатков в запросе 1С?

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

При разработке отчетов по план-фактному анализу (например, контроль выдачи спецодежды, оборудования или материалов) разработчики часто сталкиваются с задачей объединения двух наборов данных. У нас есть первая таблица с эталонными нормами и вторая таблица с фактическими остатками. Рассмотрим подробнее, как правильно написать запрос, чтобы не потерять сотрудников, которым еще ничего не выдали, и отсечь лишние данные.

Анализ исходной проблемы

Проанализируем ситуацию, описанную в задаче. У нас имеются две таблицы:

  1. Таблица норм выдачи: содержит должность, номенклатуру (вид спецодежды), положенное количество и срок использования.
  2. Регистр материалов (остатки): содержит сотрудника, его должность, выданную номенклатуру, дату выдачи и текущий остаток.

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

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

Шаг 1. Решение проблемы «потерянного сотрудника»

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

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


ВЫБРАТЬ
    Сотрудники.Сотрудник КАК Сотрудник,
    Сотрудники.Должность КАК Должность,
    ВТНормыВыдачи.Номенклатура КАК Номенклатура,
    ВТНормыВыдачи.Количество КАК НормаКоличество,
    ВТНормыВыдачи.СрокИспользования КАК СрокИспользования
ПОМЕСТИТЬ ВТ_СотрудникиНормы
ИЗ
    ВТ_СписокСотрудников КАК Сотрудники
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_НормыВыдачи КАК ВТНормыВыдачи
        ПО Сотрудники.Должность = ВТНормыВыдачи.Должность

Шаг 2. Агрегация фактических остатков

Посмотрим на частую ошибку: прямое соединение с таблицей остатков (виртуальной таблицей регистра или физической таблицей документов). Одному и тому же сотруднику могли выдать одну номенклатуру несколькими документами (например, две пары перчаток в разные дни). Если не свернуть эти данные перед соединением, левое соединение задвоит нам нормативное количество.

Сгруппируем данные из регистра материалов перед итоговым соединением:


ВЫБРАТЬ
    Остатки.ФизЛицо КАК ФизЛицо,
    Остатки.ВидСпецодежды КАК Номенклатура,
    СУММА(Остатки.КоличествоОстаток) КАК КоличествоОстаток,
    МАКСИМУМ(Остатки.ДокументПередачиДата) КАК ДатаВыдачи
ПОМЕСТИТЬ ВТ_АгрегированныеОстатки
ИЗ
    ВТ_СпецодеждаВНаличии КАК Остатки
СГРУППИРОВАТЬ ПО
    Остатки.ФизЛицо,
    Остатки.ВидСпецодежды

Шаг 3. Итоговое объединение с функцией ЕСТЬNULL

Теперь выполним финальное ЛЕВОЕ СОЕДИНЕНИЕ нашей подготовленной матрицы норм и агрегированных остатков. Соединять таблицы будем по двум ключам: сотруднику и номенклатуре.

Чтобы выполнить требование по отсечению лишней номенклатуры (которая есть в остатках, но которой нет в нормах), нам достаточно использовать именно левое соединение от временной таблицы норм. В этом случае всё, что не нашло соответствия в левой таблице, будет просто проигнорировано.

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


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

Дополнительные нюансы для реальных задач

Разберем еще несколько практических моментов, о которых стоит помнить при реализации таких запросов:

  1. Внутреннее совместительство: Сотрудник может занимать несколько должностей одновременно. Обязательно учитывайте период и актуальность кадровых данных, иначе нормы могут перемешаться.
  2. Виды номенклатуры: В нормах часто указывают не саму карточку товара, а категорию (например, просто "Сапоги резиновые"). В этом случае в таблице остатков необходимо связывать данные не напрямую по ссылке на номенклатуру, а обращаться к ее реквизиту ВидНоменклатуры или НоменклатурнаяГруппа.
  3. Расчет сроков: В 1С язык запросов позволяет вычислять плановую дату следующей выдачи. Если срок указан в месяцах, используйте функцию ДОБАВИТЬКДАТЕ(Факт.ДатаВыдачи, МЕСЯЦ, МатрицаНорм.СрокИспользования).

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

← На главную