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

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

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

Разбор постановки задачи

Представим, что у нас есть две таблицы (Таблица1 и Таблица2), содержащие поля Фамилия, Цех и НормаЧасов. Нам необходимо получить результирующую таблицу, следуя трем жестким условиям:

  1. Совпадение по фамилии и цеху: Если строка первой и второй таблицы совпадают по ключевой паре Фамилия + Цех, мы должны взять значение НормаЧасов исключительно из второй таблицы.
  2. Различие по цеху при совпадении фамилии: Если фамилия сотрудника есть в обеих таблицах, но цеха различаются, в результат должны попасть все такие строки и из первой, и из второй таблицы.
  3. Фильтрация по вхождению: Если фамилия сотрудника присутствует только в одной из таблиц (первой или второй), такие данные вообще не должны попадать в результат.

Проанализируем ситуацию: ключевая сложность здесь заключается в условии №3. Оно требует от нас предварительно определить «область интереса» — список фамилий, которые встречаются в обоих источниках данных одновременно. Рассмотрим, как это реализовать на практике.

Решение через использование временных таблиц (наиболее надежный способ)

Этот подход считается наиболее прозрачным и легко читаемым. Мы разберем его по шагам, используя механизм временных таблиц 1С.

Шаг 1: Получение списка общих фамилий. Сначала нам нужно найти пересечение множеств по полю Фамилия. Используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ, чтобы отсечь «одиночек».


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Таблица1.Фамилия КАК Фамилия
ПОМЕСТИТЬ ВТ_ОбщиеФамилии
ИЗ
    Таблица1 КАК Таблица1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица2 КАК Таблица2
        ПО Таблица1.Фамилия = Таблица2.Фамилия
;

Шаг 2: Формирование предварительных данных. Теперь соберем все записи из обеих таблиц, но только для тех сотрудников, которые попали в нашу временную таблицу ВТ_ОбщиеФамилии.


ВЫБРАТЬ
    ВТ_ОбщиеФамилии.Фамилия КАК Фамилия,
    Т1.Цех КАК Цех,
    Т1.НормаЧасов КАК НормаЧасов,
    1 КАК НомерТаблицы
ПОМЕСТИТЬ ВТ_ВсеДанные
ИЗ
    ВТ_ОбщиеФамилии КАК ВТ_ОбщиеФамилии
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица1 КАК Т1
        ПО ВТ_ОбщиеФамилии.Фамилия = Т1.Фамилия

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ВТ_ОбщиеФамилии.Фамилия,
    Т2.Цех,
    Т2.НормаЧасов,
    2
ИЗ
    ВТ_ОбщиеФамилии КАК ВТ_ОбщиеФамилии
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица2 КАК Т2
        ПО ВТ_ОбщиеФамилии.Фамилия = Т2.Фамилия
;

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


ВЫБРАТЬ
    ВТ_ВсеДанные.Фамилия КАК Фамилия,
    ВТ_ВсеДанные.Цех КАК Цех,
    // Если по этой паре есть запись из Таблицы 2, берем её
    МАКСИМУМ(ВЫБОР 
        КОГДА ВТ_ВсеДанные.НомерТаблицы = 2 ТОГДА ВТ_ВсеДанные.НормаЧасов 
        ИНАЧЕ 0 
    КОНЕЦ) КАК ЧасыИзТ2,
    // Запоминаем часы из Таблицы 1
    МАКСИМУМ(ВЫБОР 
        КОГДА ВТ_ВсеДанные.НомерТаблицы = 1 ТОГДА ВТ_ВсеДанные.НормаЧасов 
        ИНАЧЕ 0 
    КОНЕЦ) КАК ЧасыИзТ1
ПОМЕСТИТЬ ВТ_Группировка
ИЗ
    ВТ_ВсеДанные КАК ВТ_ВсеДанные
СГРУППИРОВАТЬ ПО
    ВТ_ВсеДанные.Фамилия,
    ВТ_ВсеДанные.Цех
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Группировка.Фамилия,
    ВТ_Группировка.Цех,
    ВЫБОР 
        КОГДА ВТ_Группировка.ЧасыИзТ2 > 0 ТОГДА ВТ_Группировка.ЧасыИзТ2
        ИНАЧЕ ВТ_Группировка.ЧасыИзТ1
    КОНЕЦ КАК НормаЧасов
ИЗ
    ВТ_Группировка КАК ВТ_Группировка

Решение через объединение (UNION) трех подзапросов

Рассмотрим более лаконичный метод, который часто предпочитают на экзаменах «1С:Специалист». Мы разделим задачу на три логических части и объединим их.

  1. Часть 1: Берем только те строки из Таблицы2, которые по Фамилии и Цеху совпали с Таблицей1.
  2. Часть 2: Берем строки из Таблицы1, где Фамилия есть в Таблице2, но Цех другой.
  3. Часть 3: Берем строки из Таблицы2, где Фамилия есть в Таблице1, но Цех другой.

// 1. Совпадение по ФИО и Цеху - берем из Т2
ВЫБРАТЬ
    Т1.Фамилия,
    Т1.Цех,
    Т2.НормаЧасов
ИЗ
    Таблица1 КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица2 КАК Т2
        ПО Т1.Фамилия = Т2.Фамилия
            И Т1.Цех = Т2.Цех

ОБЪЕДИНИТЬ ВСЕ

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

ОБЪЕДИНИТЬ ВСЕ

// 3. Есть в Т2, нет в Т1 по такому Цеху (но Фамилия общая)
ВЫБРАТЬ
    Т2.Фамилия,
    Т2.Цех,
    Т2.НормаЧасов
ИЗ
    Таблица2 КАК Т2
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таблица1 КАК Т1_Фам
        ПО Т2.Фамилия = Т1_Фам.Фамилия
        ЛЕВОЕ СОЕДИНЕНИЕ Таблица1 КАК Т1_Полное
        ПО Т2.Фамилия = Т1_Полное.Фамилия
            И Т2.Цех = Т1_Полное.Цех
ГДЕ
    Т1_Полное.Фамилия ЕСТЬ NULL

Проанализируем ситуацию: Данный запрос корректно отрабатывает все условия. ВНУТРЕННЕЕ СОЕДИНЕНИЕ по фамилии во втором и третьем блоках гарантирует выполнение условия №3 (отсечение уникальных фамилий). ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на NULL позволяет найти те цеха, которые не пересекаются.

Важные замечания по производительности и логике

При решении подобных задач стоит помнить о нескольких нюансах:

Рассмотренные методы позволяют гибко управлять объединением данных. Выбор между временными таблицами и множественными UNION зависит от объема данных: на больших таблицах (сотни тысяч строк) использование индексированных временных таблиц с общими фамилиями будет работать значительно быстрее за счет оптимизации плана запроса СУБД.

← На главную