При разработке отчетов или обработок в 1С часто возникает необходимость получить данные одновременно из нескольких табличных частей документа, например, из таблиц Товары и СерийныеНомера. Начинающие разработчики часто сталкиваются с проблемой: вместо ожидаемого списка товаров запрос возвращает «кучу» лишних записей, где данные дублируются или перемешиваются. Давайте разберем, почему это происходит и как построить запрос правильно.
Основная ошибка заключается в том, как таблицы указываются в операторе ВЫБРАТЬ ... ИЗ. Если вы перечисляете несколько таблиц через запятую, например:
ВЫБРАТЬ
Товары.Номенклатура,
Серии.СерийныйНомер
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Товары,
Документ.РеализацияТоваровУслуг.СерийныеНомера КАК Серии
Система выполняет так называемое декартово произведение. Это означает, что каждая строка из первой таблицы сопоставляется с каждой строкой из второй. В результате, если в документе 10 товаров и 5 серийных номеров, вы получите 50 строк. Это логически неверный результат для заполнения табличной части документа.
Чтобы данные из разных табличных частей соответствовали друг другу, необходимо использовать механизмы соединения. Наиболее универсальным является ЛЕВОЕ СОЕДИНЕНИЕ. Оно позволяет получить все данные из основной таблицы (например, Товары), даже если для них нет соответствующих записей в таблице Серии.
Рассмотрим, как правильно составить такой запрос:
ВЫБРАТЬ
Товары.НомерСтроки КАК НомерСтроки,
Товары.Номенклатура КАК Номенклатура,
Товары.Количество КАК Количество,
Серии.СерийныйНомер КАК СерийныйНомер
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ
Документ.РеализацияТоваровУслуг.СерийныеНомера КАК Серии
ПО
Товары.Ссылка = Серии.Ссылка
И Товары.НомерСтроки = Серии.НомерСтроки
ГДЕ
Товары.Ссылка = &Ссылка
КАК для именования полей. Это делает обращение к полям в коде 1С через конструкцию ВыборкаДетальныеЗаписи.ИмяПоля предсказуемым. Без КАК система может присвоить полям сложные системные имена, что приведет к ошибкам при обращении.Ссылка, но и НомерСтроки (или КлючСтроки в современных конфигурациях). Это гарантирует, что серийный номер попадет именно в ту строку товара, к которой он относится.СерийныйНомер.Ссылка в цикле вызывает «разыменование» — дополнительный запрос к базе данных для каждой строки. Старайтесь вытаскивать нужные реквизиты (Наименование, Код) сразу в тексте запроса через точку: СерийныйНомер.Код КАК КодСерийногоНомера.ВЫБРАТЬ.Разберем пример заполнения табличной части в коде 1С:
Функция ЗаполнениеТаблицы(докрел)
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ... (текст запроса с соединением)";
Запрос.УстановитьПараметр("Ссылка", докрел);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Товары.Очистить();
Пока Выборка.Следующий() Цикл
Стр = Товары.Добавить();
Стр.Наименование = Выборка.Номенклатура;
Стр.Количество = Выборка.Количество;
Стр.СерийныйНомер = Выборка.СерийныйНомер;
КонецЦикла;
КонецФункции
Теперь, благодаря использованию ЛЕВОЕ СОЕДИНЕНИЕ и корректному условию ПО, каждая строка товаров будет содержать верный серийный номер, а количество записей в выборке будет соответствовать количеству строк в табличной части документа.