Как найти сотрудника с зарплатой, наиболее близкой к средней по отделу в 1С?

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

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

Анализ задачи и выбор стратегии

Для решения нам необходимо выполнить несколько логических шагов. Основная сложность заключается в том, что среднее значение нельзя получить в той же строке, где находится текущая зарплата сотрудника, без использования специальных механизмов. Мы разберем два основных подхода: классический метод с временными таблицами (который работает на любых версиях 1С 8) и современный метод с оконными функциями (доступный в платформе 8.3.20 и выше).

Вариант 1: Классический подход через временные таблицы

Проанализируем ситуацию, когда нам нужно решить задачу стандартными средствами. Суть метода заключается в последовательном вычислении промежуточных данных и сохранении их во временные таблицы (ПОМЕСТИТЬ).

Шаг 1: Получение исходных данных и средних значений. Сначала мы выберем всех сотрудников и их зарплаты, а также рассчитаем среднюю зарплату в разрезе отделов.


ВЫБРАТЬ
    Сотрудники.Ссылка КАК Сотрудник,
    Сотрудники.Отдел КАК Отдел,
    Сотрудники.Зарплата КАК Зарплата
ПОМЕСТИТЬ ВТ_ИсходныеДанные
ИЗ
    Справочник.Сотрудники КАК Сотрудники;

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

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


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

Шаг 3: Поиск минимального отклонения. На этом этапе мы выясним, какое именно отклонение в каждом отделе является минимальным. Это критически важно, так как мы ищем "ближайшую" зарплату.


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

Шаг 4: Получение финального списка. В финальном запросе мы соединяем таблицу отклонений с таблицей минимальных отклонений по двум полям: Отдел и Отклонение. Это позволит нам получить сотрудников, чье отклонение в точности равно минимальному.


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

Вариант 2: Использование оконных функций (Платформа 8.3.20+)

Рассмотрим более современный и эффективный способ. Если ваша база работает на актуальной версии платформы, мы можем значительно сократить текст запроса и повысить его производительность, используя оконную функцию OVER(PARTITION BY ...). Это позволяет избежать многократных соединений.

Разберем по шагам логику такого запроса:

  1. Вычисляем среднюю зарплату прямо в строке сотрудника, используя AVG(...) OVER(PARTITION BY ...).
  2. Там же вычисляем модуль разности.
  3. Во втором подзапросе определяем минимальную дельту для отдела.

ВЫБРАТЬ
    Т.Сотрудник,
    Т.Отдел,
    Т.Зарплата,
    Т.Отклонение,
    МИНИМУМ(Т.Отклонение) OVER(ПАРТИЦИЯ ПО Т.Отдел) КАК МинимальноеОтклонениеПоОтделу
ПОМЕСТИТЬ ВТ_Расчет
ИЗ
    (ВЫБРАТЬ
        Сотрудники.Ссылка КАК Сотрудник,
        Сотрудники.Отдел КАК Отдел,
        Сотрудники.Зарплата КАК Зарплата,
        ABS(Сотрудники.Зарплата - СРЕДНЕЕ(Сотрудники.Зарплата) OVER(ПАРТИЦИЯ ПО Сотрудники.Отдел)) КАК Отклонение
    ИЗ
        Справочник.Сотрудники КАК Сотрудники) КАК Т;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Расчет.Сотрудник,
    ВТ_Расчет.Отдел,
    ВТ_Расчет.Зарплата
ИЗ
    ВТ_Расчет КАК ВТ_Расчет
ГДЕ
    ВТ_Расчет.Отклонение = ВТ_Расчет.МинимальноеОтклонениеПоОтделу;

Важные технические нюансы

При реализации подобных запросов следует учитывать несколько важных моментов, которые могут повлиять на корректность и скорость работы:

1. Индексация временных таблиц. Если в вашей организации работают тысячи сотрудников, обязательно добавляйте ИНДЕКСИРОВАТЬ ПО для полей, по которым происходит соединение (в нашем примере это Отдел). Это позволит СУБД быстрее сопоставлять данные.

2. Ситуация с равными отклонениями. Математически возможна ситуация, когда у одного сотрудника зарплата на 500 рублей больше средней, а у другого — на 500 рублей меньше. В этом случае оба сотрудника будут иметь одинаковый модуль отклонения. Наш запрос выведет обоих. Если по условиям задачи требуется строго один сотрудник, необходимо добавить дополнительную сортировку и конструкцию ВЫБРАТЬ ПЕРВЫЕ 1.

3. Использование ABS. В старых версиях платформы функция ABS() могла не поддерживаться в языке запросов. В таких случаях мы используем конструкцию ВЫБОР:


ВЫБОР
    КОГДА Зарплата - СредняяЗарплата > 0
        ТОГДА Зарплата - СредняяЗарплата
    ИНАЧЕ СредняяЗарплата - Зарплата
КОНЕЦ КАК Отклонение

4. Оптимизация через СКД. Если данный расчет нужен для отчета, проанализируем возможность использования Системы компоновки данных. В СКД можно создать вычисляемое поле, которое будет рассчитывать среднее значение по группировке, а затем применить отбор. Это позволит избежать написания громоздкого кода в модулях.

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

← На главную