Как реализовать вложенный запрос по условию и правильно использовать оператор ПОДОБНО в 1С

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

При разработке сложных отчетов или обработок в системе 1С:Предприятие 8 часто возникает задача соединить две таблицы данных таким образом, чтобы информация из второй таблицы подтягивалась только при соблюдении определенного условия в первой. В этой статье мы подробно разберем, как реализовать условное левое соединение, как правильно искать подстроку в полях запроса и почему может возникать ошибка "Неверные параметры ПОДОБНО".

Постановка задачи: условное левое соединение

Рассмотрим ситуацию: у нас есть основная таблица (например, список работников в документе НарядСтивидора) и дополнительная таблица с путевыми листами. Нам необходимо присоединить данные о транспортном средстве из путевых листов, но делать это нужно только для тех строк, где должность или род занятости работника связана с вождением (содержит слово "Водитель"). Для всех остальных сотрудников поля из второй таблицы должны остаться пустыми (NULL).

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

Реализация фильтрации через условия соединения

Многие начинающие разработчики пытаются ограничить выборку во вложенном запросе или через секцию ГДЕ. Однако правильнее добавить условие в конструкцию ЛЕВОЕ СОЕДИНЕНИЕ. Разберем по шагам, как это выглядит в коде:


ВЫБРАТЬ
    НарядСтивидораСписокРаботников.Ссылка КАК Ссылка,
    НарядСтивидораСписокРаботников.Работник КАК Работник,
    НарядСтивидораСписокРаботников.РодЗанятости КАК РодЗанятости,
    ВложенныйЗапрос.ТранспортноеСредство КАК ТранспортноеСредство
ИЗ
    Документ.НарядСтивидора.СписокРаботников КАК НарядСтивидораСписокРаботников
        ЛЕВОЕ СОЕДИНЕНИЕ (
            ВЫБРАТЬ
                ПутевыеЛисты.ФИО КАК ФИО,
                ПутевыеЛисты.ТранспортноеСредство КАК ТранспортноеСредство,
                ПутевыеЛисты.ДатаВремяВыезд КАК ДатаВремяВыезд,
                ПутевыеЛисты.ДатаВремяВозврат КАК ДатаВремяВозврат
            ИЗ
                Документ.СводПутевыхЛистов.ПутевыеЛисты КАК ПутевыеЛисты
        ) КАК ВложенныйЗапрос
        ПО НарядСтивидораСписокРаботников.Работник = ВложенныйЗапрос.ФИО
            И НарядСтивидораСписокРаботников.НачалоРабот >= ВложенныйЗапрос.ДатаВремяВыезд
            И НарядСтивидораСписокРаботников.ОкончаниеРабот <= ВложенныйЗапрос.ДатаВремяВозврат
            И НарядСтивидораСписокРаботников.РодЗанятости ПОДОБНО "%Водитель%"
ГДЕ
    НарядСтивидораСписокРаботников.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода

В данном примере условие ПОДОБНО "%Водитель%", добавленное в блок ПО, гарантирует, что данные путевого листа приклеятся только к тем строкам, где в колонке РодЗанятости встречается искомая подстрока. Для "Грузчика" или "Кладовщика" это условие вернет ложь, и поле ТранспортноеСредство будет заполнено значением NULL.

Разбор ошибки «Неверные параметры ПОДОБНО»

Если при попытке выполнить запрос вы получаете сообщение об ошибке "Неверные параметры ПОДОБНО", это однозначно указывает на проблему типов данных. Оператор ПОДОБНО предназначен исключительно для работы со строковыми типами.

Выясним причину ошибки:

  1. Проверка типа поля: Скорее всего, реквизит РодЗанятости является ссылкой на справочник или перечисление, а не строкой. Несмотря на то, что в интерфейсе вы видите текст (наименование), для системы это объектная ссылка.
  2. Решение для ссылочных типов: Если поле является ссылкой, использовать ПОДОБНО нельзя. В этом случае следует сравнивать значение с конкретной ссылкой или входить в состав наименования через точку: НарядСтивидораСписокРаботников.РодЗанятости.Наименование ПОДОБНО "%Водитель%".
  3. Внимание к производительности: Обращение через точку к наименованию (РодЗанятости.Наименование) создает дополнительное неявное соединение с таблицей справочника, что может замедлить запрос. Лучшим решением будет передать массив нужных должностей в параметры запроса.

Оптимизация: использование временных таблиц

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


// Шаг 1: Подготовка данных путевых листов во временную таблицу
ВЫБРАТЬ
    ПутевыеЛисты.ФИО КАК ФИО,
    ПутевыеЛисты.ТранспортноеСредство КАК ТранспортноеСредство,
    ПутевыеЛисты.ДатаВремяВыезд КАК ДатаВремяВыезд,
    ПутевыеЛисты.ДатаВремяВозврат КАК ДатаВремяВозврат
ПОМЕСТИТЬ ВТ_ПутевыеЛисты
ИЗ
    Документ.СводПутевыхЛистов.ПутевыеЛисты КАК ПутевыеЛисты
;

// Шаг 2: Основной запрос с использованием индексированной ВТ
ВЫБРАТЬ
    НарядСтивидора.Ссылка,
    НарядСтивидора.Работник,
    НарядСтивидора.РодЗанятости,
    ВТ.ТранспортноеСредство
ИЗ
    Документ.НарядСтивидора.СписокРаботников КАК НарядСтивидора
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПутевыеЛисты КАК ВТ
        ПО НарядСтивидора.Работник = ВТ.ФИО
            И НарядСтивидора.НачалоРабот >= ВТ.ДатаВремяВыезд
            И НарядСтивидора.ОкончаниеРабот <= ВТ.ДатаВремяВозврат
            И НарядСтивидора.РодЗанятости ПОДОБНО "Водитель%"
ГДЕ
    НарядСтивидора.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода

Обратите внимание на использование ПОДОБНО "Водитель%" (без знака процента в начале). Если бизнес-логика позволяет искать только по началу строки, это работает значительно быстрее, так как СУБД может использовать индексы для поиска.

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

При работе с нарядами и временем важно учитывать следующие моменты:

  1. Строгое вхождение интервалов: Условие НачалоРабот >= Выезд И ОкончаниеРабот <= Возврат означает, что работа должна быть целиком внутри периода путевого листа. Если путевой лист закрыт раньше, чем закончился наряд, соединение не сработает. Рассмотрим возможность использования пересечения интервалов.
  2. Группировка: Если в запросе используется СУММА или другие агрегатные функции, не забывайте указывать все неагрегируемые поля в секции СГРУППИРОВАТЬ ПО. Включая поле ТранспортноеСредство, так как оно может отличаться для разных записей одного и того же сотрудника.
  3. Функция ЕСТЬNULL: При левом соединении для сотрудников, не являющихся водителями, в поле ТС вернется NULL. Чтобы избежать проблем при выводе в отчет, используйте ЕСТЬNULL(ВТ.ТранспортноеСредство, ЗНАЧЕНИЕ(Справочник.ТранспортныеСредства.ПустаяСсылка)).

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

← На главную