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

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

При проектировании и доработке конфигураций на платформе «1С:Предприятие» разработчики нередко сталкиваются с ситуацией, когда несколько выбранных опций хранятся в базе данных в виде одной строки. Яркий пример — график доставки по дням недели, сохраненный в виде строки цифр (например, "13" означает доставку в понедельник и среду, а "136" — в понедельник, среду и субботу). Попытка получить текстовое представление этих дней простым запросом через классическую конструкцию ВЫБОР КОГДА приводит к тому, что система возвращает только один (первый совпавший) день или не возвращает ничего. В этой статье мы подробно разберем, почему так происходит, как решить эту задачу в рамках одного запроса и какие существуют архитектурно правильные альтернативы.

Выясняем причину: почему стандартный ВЫБОР КОГДА берет только первое значение?

Рассмотрим исходный запрос, который часто пишут начинающие разработчики:


ВЫБОР 
    КОГДА ТорговыеТочки.ГрафикДоставки = "1" ТОГДА "Понедельник" 
    КОГДА ТорговыеТочки.ГрафикДоставки = "2" ТОГДА "Вторник" 
    КОГДА ТорговыеТочки.ГрафикДоставки = "3" ТОГДА "Среда" 
    ...
КОНЕЦ КАК ДниДоставки

В этой конструкции кроются сразу две проблемы:

  1. Строгое равенство. Оператор равенства (=) сравнивает строку целиком. Если в поле ГрафикДоставки записано значение "13", то проверка ГрафикДоставки = "1" вернет ложь. Проверка ГрафикДоставки = "3" также вернет ложь. В итоге запрос вообще вернет пустое значение (NULL).
  2. Логика работы конструкции выбора. Оператор ВЫБОР КОГДА ... КОНЕЦ в SQL и в языке запросов 1С работает последовательно до первого истинного условия. Как только система находит условие, которое выполняется, она возвращает соответствующий результат и прекращает дальнейшие проверки в рамках этой конструкции. Вывести несколько разных значений из одной конструкции ВЫБОР физически невозможно.

Для того чтобы вывести все выбранные дни недели в одну колонку, нам потребуется применить конкатенацию (сложение строк) нескольких независимых конструкций ВЫБОР.

Решение 1. Конкатенация условий с оператором ПОДОБНО (Решение с форума)

Посмотрим на пример реализации, предложенный участниками форума. Вместо сравнения на строгое равенство мы будем использовать оператор поиска подстроки ПОДОБНО (LIKE в SQL) и складывать результаты работы отдельных блоков ВЫБОР. Каждый день недели анализируется в собственной независимой конструкции:


ВЫБРАТЬ
    ТорговыеТочки.Район,
    ТорговыеТочки.Участок,
    ТорговыеТочки.Наименование КАК ТорговаяТочка,
    ВЫБОР КОГДА ТорговыеТочки.ГрафикДоставки ПОДОБНО "%1%" ТОГДА "Понедельник, " ИНАЧЕ "" КОНЕЦ +
    ВЫБОР КОГДА ТорговыеТочки.ГрафикДоставки ПОДОБНО "%2%" ТОГДА "Вторник, " ИНАЧЕ "" КОНЕЦ +
    ВЫБОР КОГДА ТорговыеТочки.ГрафикДоставки ПОДОБНО "%3%" ТОГДА "Среда, " ИНАЧЕ "" КОНЕЦ +
    ВЫБОР КОГДА ТорговыеТочки.ГрафикДоставки ПОДОБНО "%4%" ТОГДА "Четверг, " ИНАЧЕ "" КОНЕЦ +
    ВЫБОР КОГДА ТорговыеТочки.ГрафикДоставки ПОДОБНО "%5%" ТОГДА "Пятница, " ИНАЧЕ "" КОНЕЦ +
    ВЫБОР КОГДА ТорговыеТочки.ГрафикДоставки ПОДОБНО "%6%" ТОГДА "Суббота, " ИНАЧЕ "" КОНЕЦ +
    ВЫБОР КОГДА ТорговыеТочки.ГрафикДоставки ПОДОБНО "%7%" ТОГДА "Воскресенье" ИНАЧЕ "" КОНЕЦ КАК ДниДоставки
ИЗ
    Справочник.ТорговыеТочки КАК ТорговыеТочки

Как это работает: запрос проверяет наличие символа "1" в строке графика. Если символ найден, к результирующей строке прибавляется "Понедельник, ". Затем аналогично проверяется "2", "3" и так далее. Все результаты склеиваются в одно длинное текстовое поле.

При всей простоте у этого метода есть существенные недостатки, о которых необходимо знать профессиональному разработчику.

Критический анализ решения с оператором ПОДОБНО

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

Решение 2. Обработка данных на стороне встроенного языка 1С (Рекомендовано)

Для исключения проблем с производительностью СУБД и получения красивого форматирования строк правильнее перенести задачу склеивания дней недели на сторону встроенного языка 1С. Запрос должен получать только сырые данные (строку цифр), а код — преобразовывать ее в читаемый вид.

Разберем по шагам создание функции форматирования:


// Функция преобразует строку вида "136" в "Понедельник, Среда, Суббота"
Функция ПолучитьПредставлениеГрафика(СтрокаЦифр) Экспорт
    
    Если ПустаяСтрока(СтрокаЦифр) Тогда
        Возврат "";
    КонецЕсли;
    
    // Заполняем соответствие дней недели
    СоответствиеДней = Новый Соответствие;
    СоответствиеДней.Вставить("1", "Понедельник");
    СоответствиеДней.Вставить("2", "Вторник");
    СоответствиеДней.Вставить("3", "Среда");
    СоответствиеДней.Вставить("4", "Четверг");
    СоответствиеДней.Вставить("5", "Пятница");
    СоответствиеДней.Вставить("6", "Суббота");
    СоответствиеДней.Вставить("7", "Воскресенье");
    
    МассивВыбранныхДней = Новый Массив;
    
    // Обходим каждый символ входящей строки
    Для Индекс = 1 По СтрДлина(СтрокаЦифр) Цикл
        Символ = Сред(СтрокаЦифр, Индекс, 1);
        ДеньНедели = СоответствиеДней.Получить(Символ);
        Если ДеньНедели <> Неопределено Тогда
            МассивВыбранныхДней.Добавить(ДеньНедели);
        КонецЕсли;
    КонецЦикла;
    
    // Склеиваем массив через запятую БЕЗ висящего знака на конце
    Возврат СтрСоединить(МассивВыбранныхДней, ", ");
    
КонецФункции

При обходе выборки результата запроса мы просто передаем значение реквизита в эту функцию и выводим в отчет красивую и чистую строку без лишних запятых.

Решение 3. Использование СКД (Вычисляемые поля)

Если ваш отчет строится с использованием Системы компоновки данных (СКД), то вы можете элегантно совместить легкий запрос и форматирование кода. Рассмотрим, как это сделать:

  1. Поместите функцию ПолучитьПредставлениеГрафика в общий модуль конфигурации (например, РаботаСКлиентамиПереопределяемый). Убедитесь, что у модуля стоят флаги "Клиент", "Сервер" и "Вызов сервера".
  2. В схеме компоновки данных перейдите на вкладку "Вычисляемые поля".
  3. Добавьте новое поле с именем ПредставлениеГрафика.
  4. В колонке "Выражение" укажите вызов вашей функции: РаботаСКлиентамиПереопределяемый.ПолучитьПредставлениеГрафика(ГрафикДоставки).
  5. В настройках вывода отчета выберите новое поле вместо исходного реквизита ГрафикДоставки.

СУБД моментально выберет простые строки из базы данных, а процессор компоновки данных быстро преобразует их в человеческий вид перед выводом пользователю.

Решение 4. Архитектурно правильное хранение данных (Best Practices)

Хранение списка значений в одном текстовом поле (строка типа "137") — это классический антипаттерн проектирования реляционных баз данных. Данные в таком виде невозможно быстро фильтровать, индексировать и анализировать. Если конфигурация находится в вашей разработке и ее структуру можно менять, рассмотрите один из правильных вариантов рефакторинга:

Какое бы решение вы ни выбрали, всегда ориентируйтесь на объем базы данных и требования к производительности системы. Для простых и редких отчетов подойдет решение с конкатенацией ПОДОБНО, для крупных учетных систем — обработка через функции общего модуля или рефакторинг структуры хранения данных.

← На главную