Работа с табличными частями в запросах 1С часто вызывает трудности у начинающих разработчиков. Типичная ситуация: вам нужно вытянуть всего одно число (например, количество часов по определенной дисциплине), но запрос упорно возвращает структуру, где внутри одной таблицы находится другая таблица. В этой статье мы разберем, почему так происходит, и как написать эффективный и лаконичный запрос для решения этой задачи.
Рассмотрим ситуацию, с которой столкнулся автор темы. При попытке выбрать данные из табличной части документа через обращение к объекту (например, Документ.ПриказЗачисление.УчебныйПлан.Дисциплины.(КоличествоЧасов)), система 1С формирует результат, в котором поле «Дисциплины» само является объектом типа РезультатЗапроса. Чтобы достать оттуда значение, программисту приходится писать вложенные циклы в коде 1С, что крайне неудобно и непроизводительно.
Рассмотрим, почему это плохо:
Проанализируем пример «извращенного» запроса, к которому сначала пришел автор. В нем используются множественные вложенные запросы в секции ИЗ:
Запрос.Текст = "ВЫБРАТЬ
| УчебныйПланДисциплины.КоличествоЧасов КАК КоличествоЧасов
|ИЗ
| Документ.УчебныйПлан.Дисциплины КАК УчебныйПланДисциплины,
| (ВЫБРАТЬ
| УчебныйПлан.Дисциплины.(...)
| ИЗ
| Документ.УчебныйПлан КАК УчебныйПлан) КАК ВложенныйЗапрос";
Такой подход избыточен. Здесь происходит соединение табличной части самой с собой через вложенные конструкции. Мы видим типичную ошибку: попытку применить логику объектного программирования (где мы идем «вглубь» объекта) к реляционным таблицам БД.
Для того чтобы получить конкретное значение из строк табличной части, нам не нужно выбирать сам документ. Мы можем обратиться напрямую к таблице этой части. В системе 1С любая табличная часть любого документа или справочника представлена в базе данных как отдельная физическая таблица.
Разберем по шагам правильный алгоритм построения запроса:
ИЗ выбираем не сам документ, а его табличную часть: Документ.УчебныйПлан.Дисциплины.ГДЕ, используя разыменование полей через точку (например, Ссылка.УчебныйГод).ПЕРВЫЕ 1.Посмотрим на пример правильного кода:
ВЫБРАТЬ ПЕРВЫЕ 1
УчебныйПланДисциплины.КоличествоЧасов КАК КоличествоЧасов
ИЗ
Документ.УчебныйПлан.Дисциплины КАК УчебныйПланДисциплины
ГДЕ
УчебныйПланДисциплины.Дисциплина = &Дисциплина
И УчебныйПланДисциплины.ПериодКонтроля = &ПериодКонтроля
И УчебныйПланДисциплины.Ссылка.УчебныйГод = &УчебныйГод
И УчебныйПланДисциплины.Ссылка.Специальность = &Специальность
И УчебныйПланДисциплины.Ссылка В (
ВЫБРАТЬ
ПриказЗачисление.УчебныйПлан
ИЗ
Документ.ПриказЗачисление КАК ПриказЗачисление
ГДЕ
ПриказЗачисление.Группа = &Группа
)
1. Использование «точечной нотации» (Разыменование)
В примере выше мы используем конструкцию УчебныйПланДисциплины.Ссылка.УчебныйГод. Важно понимать, что каждое обращение через точку к реквизиту ссылки порождает неявное левое соединение (LEFT JOIN) в SQL-запросе. Если у вас очень много таких обращений, это может замедлить работу. В простых случаях, как наш, это допустимо и делает код чище.
2. Конструкция ПЕРВЫЕ 1
Если ваша логика предполагает, что в результате запроса должна быть ровно одна строка, всегда добавляйте ПЕРВЫЕ 1. Это оптимизирует работу СУБД: как только сервер найдет первую подходящую запись, он прекратит поиск и вернет результат.
3. Обработка результата в коде 1С
Поскольку мы ожидаем только одно значение, цикл Пока Выборка.Следующий() использовать не обязательно. Рассмотрим более корректный способ извлечения данных в переменную:
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
// Инициализируем переменную значением по умолчанию
КолЧас = 0;
Если Выборка.Следующий() Тогда
КолЧас = Выборка.КоличествоЧасов;
КонецЕсли;
Возврат КолЧас;
Проанализируем ситуацию, если условий фильтрации слишком много или связи становятся сложными. В таких случаях вложенные запросы в секции ГДЕ (как В (ВЫБРАТЬ...) в нашем примере) могут работать медленно. Профессионалы 1С рекомендуют использовать временные таблицы.
Схема работы с временной таблицей:
Это позволяет оптимизатору SQL построить более эффективный план выполнения запроса. Для простых разовых выборок это может быть избыточно, но для отчетов или массовых обработок это стандарт индустрии.
Подведем итоги. Чтобы вынуть значение из табличной части и не запутаться в «матрешках» из таблиц:
Документ.Имя.ИмяТЧ).&Дисциплина, &Группа).Следуя этим правилам, вы обеспечите высокую скорость работы системы и чистоту вашего программного кода.